components / editor
editor.
split-pane markdown editor whose live preview scrolls and highlights in sync, both ways. bring your own markdown renderer (e.g. prose).
size
live preview
markdown editor
select any text on the left and a preview button appears — click it and the matching block on the right scrolls into view and both sides highlight.
the other direction
click any block in the preview. the editor scrolls to it and lays a gray streak over the matching lines.
<Editor value={md} onChange={setMd} renderMarkdown={render} />
- the streak tracks the textarea's own scroll
- editor and preview share one source of line numbers
sizepresets: sm · md · lg · xl · 2xl · screen (default, fills the viewport)
installation
bunx @justin06lee/chrome@latest add editorprops
| name | type | default | description |
|---|---|---|---|
| value * | string | - | markdown source (controlled). |
| onChange * | (value: string) => void | - | called with the next source on edit. |
| renderMarkdown * | (markdown: string, state: { highlightLine: number | null }) => ReactNode | - | renders the markdown with line-sync — typically (md, { highlightLine }) => <Prose lineSync highlightLine={highlightLine}>{md}</Prose>. |
| label | ReactNode | 'live preview' | sticky label over the preview pane. |
| placeholder | string | - | editor textarea placeholder. |
| textareaProps | Omit<ComponentProps<'textarea'>, 'value' | 'defaultValue'> | - | escape hatch onto the underlying textarea — e.g. onKeyDown for a vim keymap. handlers compose: the internal sync/selection glue runs first, then yours with the same event; className is merged. |
| transformSource | (source: string) => { body: string; lineOffset: number } | - | strip a leading front-matter region from the preview: the preview renders body while line-sync shifts by lineOffset (editor line N ↔ preview block N − lineOffset; selections in the stripped region clamp to the first block). keep the reference stable. |
| size | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'screen' | 'auto' | 'screen' | size preset setting height and width (width clamped to the container). 'screen' fills the container at viewport height (like justin06lee.dev/desk); sm–2xl step from 20×32rem up to 52×88rem; 'auto' opts out so className owns the sizing. |
| className | string | - | extra classes; h-*/w-* classes here override size. |