Code Editor
Editable, syntax-highlighted source field on CodeMirror 6, themed entirely through CSS variables.
c2-code-editor is a form control for source code: highlighting, a line-number gutter, bracket matching, undo,
multi-cursor, search and optional completion. It is form-associated, so name and value are submitted, required
validates and reset restores the value attribute — the same contract a native control has.
The engine is CodeMirror 6, as an optional peer dependency. Nothing is imported until an editor mounts, so the
package itself is under 5 kB gzipped, and an app that never installs CodeMirror still gets a working plain-textarea
field with the same value, the same input / change and the same form behaviour. ready resolves once the engine
settles and engine reads codemirror or basic.
Theming is ordinary CSS. CodeMirror renders real DOM inside the shadow root, so there is no JavaScript theme to
configure: the frame, gutter, selection, cursor and the whole syntax palette are --c2-code-editor__* custom
properties, and the token names match @c2n/code-viewer’s css-variables theme so one palette drives both. A dark
editor is different variable values and nothing else.
Grammars for javascript, typescript, jsx, tsx, html, css and json are built in and loaded on demand;
any other language comes from the languageLoader property.
The editor sizes itself to its content between --c2-code-editor--min-height and --c2-code-editor--max-height. A
height set on the element reaches the editor — the label and the supporting text keep theirs — so in a pane or a
split view give it height: 100% (or let a flex parent stretch it) and set the max height to none.
Installation
npm install @c2n/code-editorThe engine is installed alongside it — only the grammars the app actually uses:
npm install @codemirror/state @codemirror/view @codemirror/commands @codemirror/language \\
@codemirror/autocomplete @codemirror/search @lezer/highlight @codemirror/lang-javascriptUsage
Read the value the way you read any form control, and listen for input while typing or change on commit:
const editor = document.querySelector('c2-code-editor')
await editor.ready // 'ready' when CodeMirror mounted, 'basic' for the textarea fallback
editor.addEventListener('change', () => save(editor.value))
// Anything beyond the built-in grammars: no dependency on this package.
editor.languageLoader = async (id) => (id === 'python' ? (await import('@codemirror/lang-python')).python() : undefined)