Skip to content

Font Family

FontFamily adds font family styling via the TextStyle carrier mark. It provides a dropdown with 8 default typefaces, setFontFamily and unsetFontFamily commands, and a dynamic label that shows the active font name in the toolbar trigger. The font list is fully customizable, and any font is accepted from pasted HTML regardless of the configured list.

Not included in StarterKit. Add it separately.

Requires the TextStyle mark, which is automatically included as a dependency.

Select some text and pick a font from the dropdown. The dropdown trigger label updates to show the font at the cursor position. Each font item renders in its own typeface for preview.

With the default theme. The toolbar shows a font family dropdown with a dynamic label and 8 font options.

Click to try it out
import { Editor, Document, Paragraph, Text, FontFamily } from '@domternal/core';
import '@domternal/theme';
const editor = new Editor({
element: document.getElementById('editor')!,
extensions: [Document, Paragraph, Text, FontFamily],
content: '<p>Select text and pick a font from the toolbar dropdown.</p>',
});

With the full theme and ToolbarController, FontFamily renders as a dropdown with a dynamic label that shows the currently active font name. Each dropdown item renders in its own font for preview.

OptionTypeDefaultDescription
fontFamiliesstring[]8 default fontsFont names shown in the toolbar dropdown. Commands accept any font regardless of this list.

The default list includes 8 typefaces covering sans-serif, serif, and monospace:

FontCategory
ArialSans-serif
VerdanaSans-serif
TahomaSans-serif
Trebuchet MSSans-serif
Times New RomanSerif
GeorgiaSerif
Palatino LinotypeSerif
Courier NewMonospace
FontFamily.configure({
fontFamilies: ['Inter', 'Merriweather', 'Fira Code'],
})

Passing an empty array disables the toolbar dropdown entirely. No toolbar items are registered, but the commands still work.

FontFamily.configure({ fontFamilies: [] }) // no toolbar, commands only

Sets the font family on the current selection. Accepts any font family name as a string.

editor.commands.setFontFamily('Georgia');
// With chaining
editor.chain().focus().setFontFamily('Courier New').run();

Under the hood, this calls setMark('textStyle', { fontFamily }) to apply the font attribute on the TextStyle carrier mark.

Removes the font family from the current selection, resetting it to the browser default. Also cleans up empty <span> wrappers via removeEmptyTextStyle().

editor.commands.unsetFontFamily();

FontFamily does not register any keyboard shortcuts.

FontFamily does not register any input rules.

FontFamily registers a dropdown with dynamicLabel in the toolbar.

DropdownIconGroupPriorityDisplay mode
fontFamilytextAatextStyle150text

The dropdown trigger uses dynamicLabel mode with computedStyleProperty: 'font-family': instead of showing a fixed icon, it displays the name of the currently active font as text. The trigger label updates as the cursor moves through differently-styled text.

Cursor positionTrigger shows
Text with font-family: GeorgiaGeorgia
Text with font-family: 'Courier New'Courier New
Text with no explicit fontAa icon (fallback)
Text with custom font not in listFont name from inline style

The label resolution follows this order:

  1. If a dropdown item is active (cursor in text matching a configured font), show that item’s label
  2. Otherwise, read the inline font-family style at the cursor position (handles custom fonts not in the list)
  3. If no inline style found, show the textAa icon as fallback

Each font in the fontFamilies array becomes a dropdown item:

PropertyValue
namefontFamily-{name} (e.g., fontFamily-Georgia)
commandsetFontFamily
commandArgs[fontName]
isActive{ name: 'textStyle', attributes: { fontFamily: name } }
icontextAa
labelFont name (e.g., Georgia)
stylefont-family: {name} (renders the item in its own font)
priority200 - index (first font = 200, last = 193)

The style property on each item makes the font name render in its own typeface, giving users a visual preview of each font.

The theme gives the fontFamily trigger a wider label area (5rem instead of the default 2.5rem) to accommodate longer font names like “Palatino Linotype” or “Trebuchet MS”.

FontFamily does not define its own mark. It injects a fontFamily attribute into the TextStyle mark using addGlobalAttributes():

addGlobalAttributes() {
return [{
types: ['textStyle'],
attributes: {
fontFamily: {
default: null,
parseHTML: (element) => element.style.fontFamily.replace(/['"]+/g, '') || null,
renderHTML: (attributes) => {
if (!attributes.fontFamily) return null;
const value = attributes.fontFamily.includes(' ')
? `'${attributes.fontFamily}'` : attributes.fontFamily;
return { style: `font-family: ${value}` };
},
},
},
}];
}

This means FontFamily, TextColor, FontSize, and Highlight all share the same <span> wrapper:

<span style="font-family: Georgia; color: #e03131; font-size: 18px">styled text</span>

Font names with spaces are wrapped in single quotes when rendered to HTML:

<!-- Single-word font - no quotes -->
<span style="font-family: Georgia">text</span>
<!-- Multi-word font - quoted -->
<span style="font-family: 'Courier New'">text</span>

When parsing, quotes are stripped from element.style.fontFamily using .replace(/['"]+/g, ''). Browsers may add or remove quotes when reading style.fontFamily, so this normalization ensures consistent attribute values.

FontFamily declares TextStyle as both a dependency (dependencies: ['textStyle']) and includes it via addExtensions(). You do not need to add TextStyle separately.

When you call unsetFontFamily(), it:

  1. Sets the fontFamily attribute to null via setMark('textStyle', { fontFamily: null })
  2. Calls removeEmptyTextStyle() to check if the TextStyle mark has any remaining non-null attributes
  3. If all attributes are null (no font-family, no color, no font-size, no background-color), removes the <span> wrapper entirely

Fonts render as inline styles on <span> elements:

<!-- With font -->
<span style="font-family: Georgia">Serif text</span>
<!-- No font (default) - no span wrapper -->
Plain text

The fontFamilies option only controls the toolbar dropdown. The commands and parser accept any font family string. Pasted HTML with fonts like “Papyrus” or “Comic Sans MS” is preserved even if those fonts are not in the configured list.

import { FontFamily } from '@domternal/core';
import type { FontFamilyOptions } from '@domternal/core';
ExportTypeDescription
FontFamilyExtensionThe font family extension
FontFamilyOptionsTypeScript typeOptions for FontFamily.configure()

@domternal/core - FontFamily.ts