Skip to content
entergamaPublic

About

TabCode is a minimal, open-source online code editor with multi-tab editing, offline storage, document statistics and native text tools.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

TabCode

License: MIT Version PWA Dependencies PRs welcome

A code editor that runs entirely in your browser, works offline, and ships zero dependencies.

Open a project, edit across tabs, preview a multi-file site live, and keep working with the network unplugged. No build step, no backend, no package manager, no tracking.

Live demo: tabcode.pages.dev

Leia em português


Contents


Why TabCode

Most browser-based editors depend on a backend, pull megabytes from a CDN, or stop working the moment you lose connectivity. TabCode takes a different stance: the editor, the file access, the live preview, the linter and the AI assistant all run locally. Your code never leaves the device unless you explicitly point the assistant at a model, including one running on your own machine.

It is built for the small, daily edits, tweaking a static site, reviewing a config file, prototyping a snippet, where a full IDE is overkill but a plain textarea is not enough.

Zero dependencies

There is no package.json, no bundler and no framework. The tokenizer, the ZIP reader and writer, the Markdown renderer, the beautifier, the diff view and the editor itself are all written for this project. What ships is what you read.

That is a deliberate constraint, not an accident: a dependency-free static site can be audited in an afternoon, cached whole by a service worker, and hosted anywhere that serves files.

Features

Projects and files

  • Folder explorer backed by the File System Access API (real disk) or by browser storage.
  • Create, rename and delete files and folders from the tree.
  • ZIP import and export — a single wrapping folder is stripped automatically; __MACOSX artifacts and binaries are skipped on import.
  • Project-aware live preview that resolves <link>, <script src> and media references against your open tabs and the project, so a multi-file site renders as if it were served. Resizable split view, with the iframe's console piped to a panel below.
  • Global search across the whole project or just the open tabs, with regex, case-sensitive and whole-word options.
  • Command palette (Alt + Shift + P) with fuzzy search over every command.

Editing

  • A real text field under the hood. The caret, the selection, the scrolling, the word wrap and the IME are the browser's, so they behave exactly the way they do everywhere else on your system — including selection handles, the long-press menu and the magnifier on touch. See How it works.
  • Syntax highlighting for 35 languages through an in-house tokenizer and grammar set, retokenised incrementally as you type.
  • Live linting for JSON and XML.
  • Undo that groups a typed word into one step and restores the selection you had before the edit.
  • Auto-indent, bracket and quote pairing, block indent and outdent, comment toggling, line move, duplicate, join, and case tools.
  • Word autocomplete from document words and grammar keywords; trigger with Ctrl/Cmd + Space.
  • Optional minimap, indent guides, invisible characters and active-line highlight.
  • Tabs with a dirty indicator, drag-to-reorder, inline rename, middle-click to close and a context menu.

Durability

  • Autosaves to IndexedDB while you type. Reloading restores the tab order, the active tab, per-file cursor and scroll position, and reopens the project.
  • Closing a tab is undoable (Alt + Shift + T) — losing the tab does not lose the file.
  • Persistent storage is requested so the browser is less likely to evict a project under disk pressure.

Mobile

  • Tap places the caret and the system keyboard opens, because the thing you tapped is a real editable field.
  • Long-press gives you the native selection handles and the copy/paste menu your OS already provides.
  • A touch toolbar with the keys a phone keyboard lacks — Tab, brackets, arrows, selection mode. Every key is a 44 px target.
  • The status bar lifts above the virtual keyboard so the cursor position stays visible, and the toolbar sits on top of it at whatever height the keyboard actually is.

Internationalisation

  • Full UI translation in English, Portuguese (Brazil) and Spanish; the locale is remembered across sessions.
  • Every menu, modal, toast and shortcut label is translated; missing keys fall back to English.

Offline and security

  • Zero runtime dependencies and zero network calls from the editor itself.
  • A strict Content Security Policy with no unsafe-eval. The _headers file adds HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy.
  • The preview iframe is sandboxed without allow-same-origin, so previewed code runs on an opaque origin and cannot reach your files or storage.
  • Markdown is rendered by an in-house parser that builds DOM nodes instead of assigning innerHTML — the XSS class is designed out, not sanitised away.
  • Highlighted code is inserted as text nodes, never as markup, so a file's contents can never become HTML.
  • Paths are validated against traversal, uploads are size-capped (5 MB) and binaries are rejected before they reach the editor.

AI assistant

  • Configure any OpenAI-compatible endpoint — OpenAI, Groq, OpenRouter, Together, or Ollama running locally (no key, no cloud).
  • Ask about the open file or the current selection; responses stream in as they arrive.
  • The model never writes directly. Every code response goes through a diff you approve before it is applied — and applying it is a normal undo step.

Getting started

No build step. Serve the folder with any static server:

python3 -m http.server 8080
# or
npx serve .

Then open http://localhost:8080.

For production, deploy the repository root to Cloudflare Pages or any static host. The _headers file is picked up automatically by Cloudflare Pages; on other hosts, translate it to your platform's header configuration.

Browser storage and the File System Access API require a secure context — HTTPS or localhost.

How it works

The one design decision worth knowing before you read the code:

The editor is a real <textarea> with transparent glyphs, sitting on top of a <pre> that paints the same text in colour.

The browser owns the caret, the selection, the scrolling, the wrapping, the IME and the virtual keyboard. TabCode owns the paint. Nothing in the codebase measures text.

That matters because the alternative — computing glyph positions and drawing your own caret over browser-laid-out text — requires two independent measurement systems to agree forever. They don't. Ligatures, font fallback, tab stops, sub-pixel rounding, emoji and word wrap each break the agreement in their own way, and each break shows up as a caret in the wrong place. TabCode 0.5 worked that way and had exactly those bugs. Version 0.6 removed the measurement code entirely.

The two surfaces stay aligned by construction: every property that affects text layout is declared for both of them in a single CSS rule, the metric contract, at the top of assets/css/editor.css.

Repository layout

index.html              app shell, CSP, script order
sw.js                   service worker: precache + offline strategies
manifest.json           PWA manifest
_headers                security headers (Cloudflare Pages)

assets/css/
  styles.css            application chrome
  editor.css            the editor surface and the metric contract

assets/js/
  core.js               namespace, event bus, settings, limits
  editor/               the editor core
    range.js              a span between two document points
    undo.js               history, selection snapshots, coalescing
    selection.js          anchor/head pair over character offsets
    session.js            the document: lines, offsets, tokens
    view.js               the paint layer
    input.js              the bridge to the <textarea>
    text-commands.js      editing commands
    editor.js             facade consumed by the rest of the app
  highlight/            tokenizer + one grammar per language family
  fs.js, db.js, opfs-worker.js, workspace.js, files.js, zip.js
  tabs.js, tree.js, menus.js, modals.js, toast.js, commands.js
  preview.js, markdown.js, format.js, beautify.js, linter.js
  findbar.js, search.js, buffer-search.js, autocomplete.js
  ai.js, ai-ui.js
  i18n.js, theme.js, languages.js, mobile-toolbar.js, shortcuts.js
  main.js               boot order

Keyboard shortcuts

Alt is the primary modifier; add Shift for a key's secondary action. Where a Ctrl/Cmd binding also exists, both work. On mobile, the ALT button in the status bar arms the modifier for the next key press. Esc closes menus and modals.

File and project
Shortcut Action
Alt + N New file
Alt + O / Ctrl/Cmd + O Open file…
Alt + S / Ctrl/Cmd + S Save
Alt + Shift + S / Ctrl/Cmd + Shift + S Save as…
Alt + Shift + W Close tab
Alt + Shift + T Reopen closed tab
Alt + K Open project…
Alt + Shift + E Export project as ZIP
View and navigation
Shortcut Action
Alt + P Toggle preview
Alt + B / Ctrl/Cmd + B Toggle sidebar
Alt + Z Toggle word wrap
Alt + Shift + P / Ctrl/Cmd + Shift + P Command palette
Alt + ; Go to line…
Alt + Shift + → Next tab
Alt + Shift + ← Previous tab
Search
Shortcut Action
Alt + F Find in file
Alt + R Replace in file
Alt + Shift + F Search in all tabs
Alt + G Find next
Alt + Shift + G Find previous
Edit
Shortcut Action
Alt + A Select all
Alt + L Select current line
Alt + Shift + L Duplicate line
Alt + Shift + K Delete line
Alt + Shift + ↑ Move line up
Alt + Shift + ↓ Move line down
Alt + J Join lines
Alt + U Uppercase selection
Alt + Shift + U Lowercase selection
Alt + / Toggle line comment
Tab / Shift + Tab Indent / outdent
Ctrl/Cmd + Z / Ctrl/Cmd + Shift + Z Undo / redo

Caret movement, word jumps, Home/End, page keys, shift-selection and the clipboard are your browser's and your OS's — they are not rebound.

AI and settings
Shortcut Action
Alt + I / Ctrl/Cmd + I Ask the AI assistant
Alt + , Settings
Alt + Shift + / About and shortcuts

Known limitations

  • Browser storage is not your disk. A project imported from a ZIP lives inside the browser's storage quota. Clearing site data deletes it. TabCode requests persistent storage, but the browser has the final say — export to ZIP for anything you cannot afford to lose.
  • Firefox, Safari and mobile: no folder-from-disk. Use ZIP import. This is not a temporary gap; the File System Access API's disk pickers are Chromium-desktop only.
  • No virtualisation. The whole document is in the DOM, which is what lets the browser own wrapping and hit-testing. Files above 20,000 lines drop syntax colour automatically and stay editable.
  • iOS zooms when you focus a field below 16 px. The editor text is the input field now, so the old workaround (an invisible 16 px textarea) no longer applies. Keep the editor font at 16 px or larger on phones.
  • The iOS magnifier shows transparent text. The visible glyphs live in the paint layer, which the magnifier does not capture. Cosmetic, and the price of native selection.
  • Renaming a folder is not supported (only files). Renaming copies and deletes; doing that across a subtree half-way would leave the project broken, so it is refused instead.
  • Replace-all only touches open tabs — rewriting closed files would be a mass edit with no undo.
  • Formatting uses the built-in beautifier (indentation-based). Adequate for daily use, not a replacement for Prettier.
  • ZIP compression requires CompressionStream (Chrome 80+, Firefox 113+, Safari 16.4+). Without it, ZIPs are still written — just uncompressed.

Non-goals

Listed so nobody spends a weekend on a pull request that will be declined:

  • A build step, a bundler or npm dependencies. The constraint is the point.
  • Language servers, type checking or refactoring tools. They need a runtime TabCode does not have.
  • Being VS Code. TabCode is for quick edits in a browser tab, including on a phone.
  • Telemetry or analytics of any kind.

Browser support

TabCode targets modern evergreen browsers. The full experience — disk folder access, persistent storage, the OPFS worker — is available on Chromium-based desktop browsers. Firefox, Safari and mobile browsers work with the reduced feature set described above.

Contributing

Contributions are welcome. Read CONTRIBUTING.md first: it covers the code conventions, how to run and test locally, what a good pull request looks like, and how to report a security issue.

Short version: plain HTML, CSS and JavaScript; no build step; no runtime dependencies; English for code, comments and user-facing strings; open an issue before a large change.

License

MIT © Gabriel Masson

About

TabCode is a minimal, open-source online code editor with multi-tab editing, offline storage, document statistics and native text tools.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages