Skip to content

Quick Start

Galley is a controlled React component. Store Markdown in application state and pass it to value.

import { useRef, useState } from 'react';
import { GalleyEditor, type GalleyHandle } from '@inkyquill/galley-editor';
import '@inkyquill/galley-editor/style.css';
export function MarkdownEditor() {
const editor = useRef<GalleyHandle>(null);
const [value, setValue] = useState('# Release notes\n\nStart writing...');
return (
<GalleyEditor
ref={editor}
value={value}
onChange={setValue}
ariaLabel="Release notes editor"
placeholder="Write Markdown..."
minRows={12}
theme="auto"
onSubmit={() => save(value)}
/>
);
}

The editor supports three modes:

ModeBehavior
liveMarkdown syntax is hidden outside the active node.
markdownRaw Markdown stays visible.
previewRendered view only; editing is disabled.
<GalleyEditor mode="live" onModeChange={setMode} />

Setting editable={false} forces preview mode.

The toolbar and footer are enabled by default. Disable them when your app provides its own chrome:

<GalleyEditor toolbar={false} footer={false} />

The toolbar remains open by default for existing integrations. For a quieter writing surface, start it collapsed and let the writer reveal it with the small footer button:

<GalleyEditor toolbar={{ defaultOpen: false }} />

Or customize slots while keeping Galley’s built-in controls:

<GalleyEditor
toolbar={{
before: <strong>Draft</strong>,
after: ({ editor }) => (
<button type="button" onClick={() => editor?.execCommand('insertHr')}>
Divider
</button>
),
}}
footer={{
characterCount: true,
wordCount: true,
after: ({ mode }) => <span>{mode}</span>,
}}
/>

Use the ref for focus, selection, document updates, commands, and the CodeMirror escape hatch:

editor.current?.focus();
editor.current?.insertText('**Important**');
editor.current?.execCommand('toggleHeading', 2);
editor.current?.scrollSelectionIntoView();

For CodeMirror extensions that are not part of Galley’s public props, use extensions at render time or addExtension() at runtime.

const disposable = editor.current?.addExtension(myExtension);
disposable?.remove();

Prefer stable extension arrays when passing extensions as a prop.