Skip to content

Commands

Galley exposes editor actions as commands. Commands can be called through the imperative ref, bound to CodeMirror keymaps, or wrapped by your own toolbar.

import { useRef } from 'react';
import { GalleyEditor, type GalleyHandle } from '@inkyquill/galley-editor';
export function Editor() {
const editor = useRef<GalleyHandle>(null);
return (
<>
<button type="button" onClick={() => editor.current?.execCommand('toggleBold')}>
Bold
</button>
<GalleyEditor ref={editor} />
</>
);
}

Most editing commands return true when they changed the document and false when the command cannot apply at the current selection.

Use commands for app-owned toolbars, menus, palettes, or side panels. Prevent mouse-down from taking focus before command execution when the command should apply to the current editor selection.

const editor = useRef<GalleyHandle>(null);
function run(command: string, ...args: unknown[]) {
editor.current?.execCommand(command, ...args);
}
return (
<>
<div className="app-toolbar">
<button
type="button"
onMouseDown={(event) => event.preventDefault()}
onClick={() => run('toggleBold')}
>
Bold
</button>
<button
type="button"
onMouseDown={(event) => event.preventDefault()}
onClick={() => run('insertTable')}
>
Table
</button>
<button
type="button"
onMouseDown={(event) => event.preventDefault()}
onClick={() => run('insertImage', 'Alt text', '/uploads/image.png')}
>
Image
</button>
</div>
<GalleyEditor ref={editor} toolbar={false} />
</>
);

Keep the built-in toolbar when it already fits your workflow and use toolbar.icons or toolbar slots for lighter customization.

Galley includes CodeMirror’s search panel. Press Ctrl+F on Windows/Linux or Cmd+F on macOS while the editor is focused. Search also works in preview and read-only editors; replacement controls are omitted in those modes.

Open the same panel from an application toolbar through GalleyHandle:

import { useRef } from 'react';
import { GalleyEditor, type GalleyHandle } from '@inkyquill/galley-editor';
export function SearchableEditor() {
const editor = useRef<GalleyHandle>(null);
return (
<>
<button type="button" onClick={() => editor.current?.openSearch()}>
Find in document
</button>
<GalleyEditor ref={editor} />
</>
);
}

The existing findInDocument() helper remains useful when an application needs matching ranges as data instead of the built-in interactive panel.

Inline formatting:

CommandDescription
toggleBoldToggle **bold**.
toggleItalicToggle *italic*.
toggleCodeToggle inline backticks.
toggleStrikethroughToggle ~~strikethrough~~.

Block formatting:

CommandDescription
toggleHeading(level)Toggle an ATX heading from level 1 to 6.
toggleBulletListToggle unordered list markers.
toggleOrderedListToggle ordered list markers.
toggleCheckListToggle task-list markers.
insertCodeBlock(language?)Insert a fenced code block.
insertTableInsert a starter pipe table.
insertHrInsert a horizontal rule.

Editing and navigation:

CommandDescription
indent / outdentAdjust indentation.
duplicateLineDuplicate the current line or selected lines.
sortSelectedLines(options?)Sort selected lines.
swapLineUp / swapLineDownMove lines up or down.
insertLineBefore / insertLineAfterInsert a blank line around the current line.
jumpToHash(hash)Move to a matching heading.
findInDocument(needle, opts?)Return matching ranges.
undo / redo / selectAllStandard document actions.

Links and images:

CommandDescription
insertLink(label?, url?)Insert a Markdown link.
insertImage(alt?, url?)Insert a Markdown image.
updateImageMetadata(input)Update the selected image.
clearImageDimensionsRemove width and height metadata.

Tables:

CommandDescription
normalizeTableSerialize selected tables into Galley’s canonical pipe-table format.
commitTableCell(ref, text)Replace a rendered cell’s text.
insertTableRowBefore / insertTableRowAfterAdd a body row around the current row.
deleteTableRowDelete the current body row.
insertTableColumnBefore / insertTableColumnAfterAdd a column around the current column.
deleteTableColumnDelete the current column.
setTableColumnAlignment(alignment)Update column alignment.
revealTableSourcePut focus back into the table source.

DEFAULT_KEYMAP is exported for reuse. Galley installs it by default.

KeyCommand
Mod-DduplicateLine
Alt-ArrowUpswapLineUp
Alt-ArrowDownswapLineDown
Mod-Alt-ArrowUpinsertLineBefore
Mod-Alt-ArrowDowninsertLineAfter
Mod-KinsertLink
Mod-BtoggleBold
Mod-ItoggleItalic
Mod-Zundo
Mod-Shift-Zredo
Mod-AselectAll

Use the function form of keymap to extend the defaults:

<GalleyEditor
keymap={(defaults) => [
...defaults,
{
key: 'Mod-Shift-8',
run(view) {
return Boolean(view);
},
},
]}
/>

Use the array form only when you want to replace every default binding.

Buttons in Galley’s built-in toolbar append their effective command shortcut to the hover title, such as Bold (⌘B) on macOS or Bold (Ctrl+B) elsewhere. The accessible name remains Bold.

Array-form keymaps replace the defaults, so removed commands lose their shortcut hint. Function-form keymaps can preserve, remove, or remap command metadata. Keep the command field when cloning a DEFAULT_KEYMAP binding if the built-in toolbar should display the remapped key.

Register custom commands after mount:

editor.current?.registerCommand('insertCallout', (view) => {
view.dispatch(view.state.replaceSelection(':::note\nWrite a note.\n:::'));
return true;
});
editor.current?.execCommand('insertCallout');

Custom commands take precedence over built-ins with the same name. Prefer unique names for app-specific behavior so future Galley releases do not surprise your command registry.