Skip to main content

Custom Editor

Live.Editor accepts renderEditor to fully replace the built-in CodeMirror editing surface — the example below uses a plain <textarea>. It still syncs to the shared preview code automatically, exactly like the default editor.

import { useState } from 'react';

import Live from '@jbpark/live-editor';

export default function CustomEditor() {
const [value, setValue] = useState('// your code');

return (
<Live>
<Live.Preview
showError
dynamicTailwind
frame={{ mode: 'shadow', syncStyle: true }}
/>
<Live.Editor
value={value}
onChange={setValue}
renderEditor={({ value: text, onChange }) => (
<textarea
value={text}
onChange={e => onChange(e.target.value)}
spellCheck={false}
style={{ width: '100%', height: '100%', fontFamily: 'monospace' }}
/>
)}
/>
</Live>
);
}

The renderEditor render prop receives an EditorRenderData object with three fields:

FieldTypeDescription
valuestringCurrent code.
onChange(value: string) => voidCommit an edit — wire this into your editing surface's own change handler.
formatCode(code: string) => Promise<string>The same prettier-based formatting the built-in editor's Cmd+S uses. Call it to offer format-on-save without reimplementing prettier wiring yourself.

Wire value/onChange into any editing surface you like (a <textarea>, Monaco, your own component) — the shared preview stays in sync through Live's context. formatCode is entirely optional; the example above skips it and just does a raw <textarea> with no formatting.