Search page titles, headings and text across the docs.

Extensions

On this page

Extension catalogue

Use this page to find the extensions you need: what each one does, how to add it, and the commands, queries, keys, and typing shortcuts it brings.

Every extension below ships today in Rust, TypeScript, and Dart. Names match TipTap’s, so documents move between TipTap and canvist as JSON without conversion.

How to add an extension

LanguageAdd an extensionAdd the whole StarterKit
TypeScriptcreateEngine([bold, heading])createEngine()
RustEngine::new(|b| b.add(Bold))Engine::starter_kit()
DartEngineBuilder()..add(Extensions.bold)Engine.starterKit()

In TypeScript, import each extension by name from @canvist/headless. In Rust, import it from canvist_extensions (re-exported as canvist_headless::canvist_extensions). Mod means Cmd on Apple platforms and Ctrl elsewhere.

In the Typing columns, block shortcuts such as ##, -, and [ ] fire when you type a space after them at the start of a line. Mark shortcuts such as **text** fire when you type the closing characters.

Always included

Every TypeScript and Dart engine has these, so you never add them yourself. In Rust, Engine::new registers exactly what you add: add Document, Paragraph, and BaseKeymap yourself, or start from StarterKit::add_all, which includes them.

  • Document and paragraph. The root, and plain paragraphs. Command setParagraph, query isParagraph, key Mod-Alt-0.
  • Standard keys. Typing, Enter, Backspace, Delete, Mod-a, the arrow keys with Shift, Alt, and Mod, and the macOS Emacs keys (Ctrl-a, Ctrl-e, Ctrl-k, …).
  • Undo an input rule. Backspace right after a typing shortcut fires puts back what you typed. Type ##, press Backspace, and you have ## again instead of a heading.

Text formatting

Bold

Bold text. Adds the bold mark.

CommandsQueriesKeysTyping
toggleBold, setBold, unsetBoldisBoldMod-b**text**, __text__
import { bold, createEngine } from "@canvist/headless";

const doc = (await createEngine([bold])).parse("text", "Ship it");
doc.selectAll();
doc.commands.toggleBold();
console.log(doc.export("html"));
// <p><strong>Ship it</strong></p>

Italic

Italic text. Adds the italic mark.

CommandsQueriesKeysTyping
toggleItalic, setItalic, unsetItalicisItalicMod-i*text*, _text_
import { createEngine, italic } from "@canvist/headless";

const doc = (await createEngine([italic])).create();
doc.typeText("A *quiet* word");
console.log(doc.export("html"));
// <p>A <em>quiet</em> word</p>

Underline

Underlined text. Adds the underline mark. Markdown has no underline, so Markdown export drops it; HTML and JSON keep it.

CommandsQueriesKeys
toggleUnderline, setUnderline, unsetUnderlineisUnderlineMod-u
import { createEngine, underline } from "@canvist/headless";

const doc = (await createEngine([underline])).parse("text", "Sign here");
doc.selectAll();
doc.commands.setUnderline();
console.log(doc.export("html"));
// <p><u>Sign here</u></p>

Strike

Struck-through text. Adds the strike mark.

CommandsQueriesKeysTyping
toggleStrike, setStrike, unsetStrikeisStrikeMod-Shift-s~~text~~
import { createEngine, strike } from "@canvist/headless";

const doc = (await createEngine([strike])).parse("markdown", "~~old~~ new");
console.log(doc.export("html"));
// <p><s>old</s> new</p>

Code

Inline code. Adds the code mark. Code excludes the other marks: text can’t be bold and code at once.

CommandsQueriesKeysTyping
toggleCode, setCode, unsetCodeisCodeMod-e`text`
import { code, createEngine } from "@canvist/headless";

const doc = (await createEngine([code])).create();
doc.typeText("Run `deno test` first");
console.log(doc.export("markdown"));
// Run `deno test` first

Links with an href. Adds the link mark. URLs become links when you type a space after them and when you paste them. Typing at the edge of a link doesn’t extend it.

CommandsQueriesTyping
setLink({ href }), unsetLinklinkHrefA URL followed by a space
import { createEngine, link } from "@canvist/headless";

const doc = (await createEngine([link])).parse("text", "Read the guide");
doc.select({ path: [0], offset: 9 }, { path: [0], offset: 14 });
doc.commands.setLink({ href: "https://example.com" });
console.log(doc.export("markdown"));
// Read the [guide](https://example.com)

In Rust, Link { autolink: false, link_on_paste: false } turns off automatic linking.

Blocks

Heading

Headings, levels 1 to 6. Adds the heading block with a level attribute.

CommandsQueriesKeysTyping
toggleHeading({ level }), setHeading({ level })headingLevelMod-Alt-1 to Mod-Alt-6# to ######
import { createEngine, heading } from "@canvist/headless";

const doc = (await createEngine([heading])).parse("text", "Overview");
doc.selectAll();
doc.commands.setHeading({ level: 2 });
console.log(doc.export("markdown"));
// ## Overview

In Rust, Heading { max_level: HeadingLevel::H3 } offers only levels 1 to 3.

Blockquote

Quotes that wrap other blocks. Adds the blockquote block.

CommandsQueriesKeysTyping
toggleBlockquoteisBlockquoteMod-Shift-b>
import { blockquote, createEngine } from "@canvist/headless";

const doc = (await createEngine([blockquote])).parse(
	"text",
	"Less, but better.",
);
doc.selectAll();
doc.commands.toggleBlockquote();
console.log(doc.export("html"));
// <blockquote><p>Less, but better.</p></blockquote>

Code block

Blocks of code with an optional language. Adds the codeBlock block with a language attribute. Enter inserts a new line inside the block; Enter on an empty last line leaves it.

CommandsQueriesKeysTyping
toggleCodeBlock({ language }), setCodeBlock({ language })isCodeBlock, codeBlockLanguageMod-Alt-c``` or ```rust then space
import { codeBlock, createEngine } from "@canvist/headless";

const doc = (await createEngine([codeBlock])).parse("text", "let x = 1;");
doc.selectAll();
doc.commands.setCodeBlock({ language: "rust" });
console.log(doc.query.codeBlockLanguage());
// rust

Horizontal rule

A dividing line between blocks. Adds the horizontalRule block.

CommandsTyping
setHorizontalRule---, ___, or ***
import { createEngine, horizontalRule } from "@canvist/headless";

const doc = (await createEngine([horizontalRule])).parse(
	"markdown",
	"Above\n\n---\n\nBelow",
);
console.log(doc.export("html"));
// <p>Above</p><hr><p>Below</p>

Hard break

A line break inside a paragraph. Adds the hardBreak embed.

CommandsKeys
setHardBreakShift-Enter, Mod-Enter
import { createEngine, hardBreak } from "@canvist/headless";

const doc = (await createEngine([hardBreak])).parse("text", "Line one");
doc.select({ path: [0], offset: 8 });
doc.commands.setHardBreak();
doc.insertText("Line two");
console.log(doc.export("html"));
// <p>Line one<br>Line two</p>

Lists

Lists need list items. Adding bulletList or orderedList adds listItem for you.

Bullet list

CommandsQueriesKeysTyping
toggleBulletListisBulletListMod-Shift-8-, *, or +

Ordered list

Numbered lists with a start number.

CommandsQueriesKeysTyping
toggleOrderedList, setOrderedListStart({ start })isOrderedList, orderedListStartMod-Shift-71.

List item

The items inside bullet and ordered lists. Enter splits an item, Tab nests it under the item before, and Shift-Tab lifts it out.

CommandsKeys
splitListItem, sinkListItem, liftListItemEnter, Tab, Shift-Tab, Backspace
import { bulletList, createEngine, orderedList } from "@canvist/headless";

const doc = (await createEngine([bulletList, orderedList])).create();
doc.typeText("- milk");
doc.press("Enter");
doc.typeText("eggs");
doc.press("Tab");
console.log(doc.export("markdown"));
// - milk
//   - eggs

Task list

Checklists. Adds the taskList block and taskItem blocks with a checked attribute. It brings its own items, so it doesn’t need listItem.

CommandsQueriesKeysTyping
toggleTaskList, toggleTask, setTaskChecked({ checked }), splitTaskItem, sinkTaskItem, liftTaskItemisTaskList, isTaskCheckedMod-Shift-9[ ] or [x]
import { createEngine, taskList } from "@canvist/headless";

const doc = (await createEngine([taskList])).parse(
	"markdown",
	"- [ ] Write docs",
);
doc.select({ path: [0, 0, 0], offset: 0 });
doc.commands.toggleTask();
console.log(doc.export("markdown"));
// - [x] Write docs

Editing behaviour

History

Undo and redo. Without it, undo() and redo() still work from code; History adds the commands and keys.

CommandsKeys
undo, redoMod-z, Mod-Shift-z, Mod-y

Trailing node

Keeps an empty paragraph at the end of the document, so there’s always somewhere to type below a list, quote, or code block. It has no commands.

Coming soon

These extensions are planned, in roughly this order. Each will follow the same pattern: typed commands, queries, and TipTap-compatible JSON.

  • Tables: merged cells, column resizing, and cell selection.
  • Images, with resizing, plus video, audio, and file attachments.
  • Mentions, emoji, and slash commands, on one shared suggestion system.
  • Text style: highlight, colour, font family and size, subscript, superscript, and text alignment.
  • Editor helpers: placeholder, character count, find and replace, table of contents, and drag handles.
  • Comments, version history, and tracked changes.

To see where each one stands, watch the releases.

Docs