The Atomic Editor demo showcases a CodeMirror 6 markdown editor that mixes WYSIWYG tables, live inline preview, per‑language syntax highlighting and task‑list checkboxes. While the demo highlights impressive UI tricks, the underlying architecture still relies on lazy‑loaded grammars and a custom chunking routine, and many features remain experimental or limited to the demo environment.
What the demo claims
- Obsidian‑style live preview – inline rendering of markdown elements (tables, links, task checkboxes) while the cursor is inside the source.
- WYSIWYG tables – clicking a cell opens an in‑place editor; markdown delimiters appear only when the cursor enters the cell.
- Per‑language syntax highlighting – fenced code blocks load the appropriate CodeMirror grammar only when the fence becomes visible.
- Interactive task lists – checkboxes toggle on click, and pressing Enter continues or dedents the list automatically.
- Wiki‑style linking –
[[link]]autocomplete and Cmd/Ctrl‑click navigation, with raw rendering inside inline code. - Lazy loading – the demo advertises that the TypeScript grammar (or any other language) is fetched from the network only when a matching fence appears on screen.
What’s actually new under the hood
1. CodeMirror 6 integration
The editor is built on CodeMirror 6, the modular rewrite of the classic CodeMirror library. Unlike the monolithic CM 5, CM 6 lets you compose extensions for syntax highlighting, folding, and UI widgets. Atomic Editor uses the @codemirror/lang-markdown package together with @codemirror/language-data to provide a base markdown parser, then adds a few custom extensions:
- A lazy‑load wrapper that intercepts fenced‑code blocks, inspects the language identifier, and dynamically imports the corresponding language support module (e.g.,
@codemirror/lang-javascript). This mirrors the approach described in the CM 6 docs for on‑demand language loading. - A WYSIWYG table widget that replaces the default markdown rendering with a content‑editable
<table>element. The widget listens for cursor movement events and toggles the visibility of markdown delimiters (|,---) based on the active cell. - Task‑list checkboxes are implemented as a custom
Decorationthat renders an HTML<input type="checkbox">overlay. The overlay updates the underlying markdown text when the user toggles the box, keeping the source and view in sync.
2. The tiny markdown chunker
The demo includes a hand‑rolled chunkMarkdown function that splits a document into double‑newline blocks. This is not a full parser; it simply groups paragraphs, tables, and code fences for lazy loading. The function is deliberately lightweight to keep the demo responsive, but it also means the editor cannot correctly handle nested structures that cross block boundaries (e.g., a list that contains a fenced code block). The code is open‑source and lives in the demo’s GitHub repository: https://github.com/atomic-editor/demo/blob/main/src/chunkMarkdown.ts
3. UI polish built on top of CM 6 widgets
The demo’s “click‑to‑edit” table cells, inline link unfolding, and dark‑mode rendering are all achieved with CM 6’s view plugins and theme extensions. For example, the link unfolding uses a HoverTooltip that shows the raw URL when the cursor hovers over a rendered link, but only if the cursor is inside a code span does the tooltip stay hidden.
Limitations and what remains experimental
| Area | Current state in the demo | Practical impact |
|---|---|---|
| Full markdown spec compliance | Only a subset is supported (headings, tables, task lists, fenced code, wiki links). Features like footnotes, definition lists, and HTML blocks are missing. | Documents that rely on those extensions will render incorrectly or lose data when saved. |
| Lazy grammar loading latency | The first time a language fence appears, the browser fetches a separate JavaScript bundle (~30‑50 KB). In high‑latency environments this can cause a noticeable pause before syntax highlighting appears. | Users may see a flash of unstyled code, which can be confusing in fast‑editing workflows. |
| Table editing robustness | The WYSIWYG table widget works for simple cells, but complex markdown inside a cell (e.g., nested lists or multi‑line code) is not fully supported; the widget falls back to raw markdown view. | Power users who embed rich content in tables will hit a wall. |
| Collaborative editing | No built‑in CRDT or OT layer; the demo is a single‑user client‑side editor. | Real‑time collaboration would require an additional backend or integration with services like Yjs. |
| Performance on large files | The chunking approach reduces initial load, but the editor still holds the entire document in memory. Tests with files > 5 MB show noticeable lag when scrolling. | Not suitable for massive knowledge bases without further optimization. |
| Accessibility | The demo relies heavily on mouse interactions (click‑to‑edit, hover tooltips). Keyboard‑only navigation works for basic editing but not for all widgets (e.g., table cell focus). | Users who depend on screen readers or keyboard navigation may encounter barriers. |
Why it matters (and why the hype should be tempered)
Atomic Editor’s demo is a useful proof‑of‑concept for mixing WYSIWYG interactions with a source‑code‑centric editor. It shows that CodeMirror 6 can be extended to provide a near‑Obsidian experience without abandoning the underlying markdown text. However, the demo does not yet constitute a production‑ready editor:
- The lazy‑loading mechanism is clever but introduces a network dependency that can degrade the editing flow.
- The custom chunker is a shortcut that sidesteps the need for a full markdown AST, which limits feature completeness.
- Many UI niceties (inline link unfolding, task‑list handling) are tightly coupled to the demo’s CSS and may break when the component is used in a different design system.
For developers interested in building a similar editor, the takeaways are:
- Start with CM 6’s official markdown language support – it already handles most of the spec and can be extended with
LanguageSupportobjects. - Implement lazy loading at the language‑module level – the demo’s pattern (
import('@codemirror/lang-<lang>')) works, but consider bundling the most common languages to avoid the first‑load pause. - Separate UI widgets from the core parser – the table widget and task‑list decorations should be optional extensions that can be turned off for pure‑text workflows.
- Plan for scalability – if you need to support large vaults, look into incremental parsing (e.g.,
@lezerincremental trees) and virtual scrolling. - Invest in accessibility early – CM 6 provides keyboard shortcuts and ARIA roles; extending them correctly will save retro‑fit effort later.
Bottom line
The Atomic Editor demo is an interesting showcase of what’s possible with CodeMirror 6 when you combine lazy grammar loading, custom view plugins, and a few UI tricks. It is not a finished product, and the current implementation has clear constraints around spec coverage, performance on large files, and accessibility. For teams that want a markdown editor with live preview and interactive elements, the demo provides a solid starting point, but expect to spend additional engineering effort to turn it into a reliable, feature‑complete tool.
Further reading
- CodeMirror 6 documentation on language loading: https://codemirror.net/6/docs/guide/#lazy-loading
- The demo’s source repository (includes the chunker and widget code): https://github.com/atomic-editor/demo
- A discussion of WYSIWYG markdown editors in the CM 6 community: https://discuss.codemirror.net/t/wysiwyg-markdown/1234
Comments
Please log in or register to join the discussion