CodeEditor
Lightweight code editor — a native textarea overlaid on a syntax-highlighted layer, with line numbers and Tab indent.
Category: inputs · WCAG 2.1-AA · editor, code, syntax-highlighting, textarea, inputs
States
- default
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled value |
defaultValue | string | — | Initial value for uncontrolled use |
onValueChange | (value: string) => void | — | Called with the new text on every edit |
language | string | plaintext | Grammar name (plaintext/json/javascript/typescript/css/html/markdown/bash) |
lineNumbers | boolean | true | Show the line-number gutter |
tabSize | number | 2 | Spaces per tab stop |
insertSpaces | boolean | true | Insert spaces vs a literal tab on Tab |
wrap | boolean | false | Soft-wrap long lines instead of scrolling horizontally |
readOnly | boolean | false | When true, the value is shown but cannot be edited. |
disabled | boolean | false | When true, disables the control and removes it from the tab order. |
placeholder | string | — | Placeholder text shown when the field is empty. |
label | string | — | Accessible label (defaults to the i18n "Code editor") |
onSave | (value: string) => void | — | Called on Mod-S; the browser save dialog is suppressed |
bracketMatching | boolean | false | Highlight the bracket matching the one adjacent to the caret |
theme | EditorTheme | — | Per-instance --cascivo-editor-* overrides; swapping it re-themes live |
keymap | KeyMap | — | Extra key bindings merged over the built-ins (user wins on a chord) |
decorations | Decoration[] | ((value: string) => Decoration[]) | — | Extra offset-range → CSS class decorations |
commands | SlashCommand[] | — | Slash-command entries; typing "/" opens a filtered menu. Omit to disable. |
ref | Ref<CodeEditorHandle> | — | Imperative handle: applyEdit / getSelection / focus / undo / redo / openFind / openCommandMenu |
className | string | — | Additional CSS class names merged onto the root element. |
Design tokens
--cascivo-editor-bg--cascivo-editor-fg--cascivo-editor-gutter-bg--cascivo-editor-gutter-fg--cascivo-editor-gutter-active--cascivo-editor-current-line--cascivo-editor-selection--cascivo-editor-border--cascivo-editor-match--cascivo-editor-match-current--cascivo-editor-bracket
When to use
- Editing code or config inline — JSON, snippets, web languages — with line numbers and syntax colors
- A lightweight, themeable code field where a full IDE editor (Monaco/CodeMirror) would be overkill
- Editing Markdown notes — find/replace, real undo/redo, save, and selection-preserving external sync
- Editing long-form Markdown — generated docs, concatenated books, big notes — windowed (viewport-scoped) tokenization keeps scrolling/typing smooth well past ~5,000 lines
When not to use
- You need IntelliSense/LSP, multi-cursor, folding, a minimap, or diff view — use a full editor framework
- Plain prose or a single-line value — use Textarea or Input
- Sustained editing of 100k+-line documents — use a full editor framework / dedicated worker pipeline (the windowed tokenizer keeps per-render work O(viewport), but a worker offload is intentionally out of scope)
- Soft-wrap (wrap) on a very large document — rendering is O(n) under wrap; disable wrap above ~10k lines for sustained editing
Examples
Basic editor
import { CodeEditor } from '@cascivo/editor'
import '@cascivo/editor/styles.css'
<CodeEditor language="typescript" lineNumbers defaultValue={'const x = 1\n'} />Controlled
<CodeEditor language="json" value={value} onValueChange={setValue} />Notes editing — find, save, brackets
<CodeEditor
language="markdown"
value={doc}
onValueChange={setDoc}
onSave={save} // Mod-S
bracketMatching
/> // Mod-F to searchSlash commands
Type "/" to open a filtered command menu; arrows + Enter insert.
const commands = [
{ id: 'fence', label: 'Code block', keywords: ['code'], insert: '\u0060\u0060\u0060\n\n\u0060\u0060\u0060' },
{ id: 'todo', label: 'TODO', insert: '// TODO: ' },
{ id: 'date', label: 'Date', run: (e) => e.applyEdit(e.getSelection(), new Date().toISOString()) },
]
<CodeEditor language="markdown" commands={commands} />