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.
Live Playground
Section titled “Live Playground”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.
Vanilla JS preview - Angular components produce the same output
Vanilla JS preview - React components produce the same output
Plain editor without the theme. The font buttons above apply fonts programmatically.
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.
import { Component, signal } from '@angular/core';import { DomternalEditorComponent, DomternalToolbarComponent } from '@domternal/angular';import { Editor, Document, Paragraph, Text, FontFamily } from '@domternal/core';
@Component({ selector: 'app-editor', imports: [DomternalEditorComponent, DomternalToolbarComponent], templateUrl: './editor.html',})export class EditorComponent { editor = signal<Editor | null>(null); extensions = [Document, Paragraph, Text, FontFamily]; content = '<p>Select text and pick a font from the toolbar dropdown.</p>';}@if (editor(); as ed) { <domternal-toolbar [editor]="ed" />}<domternal-editor [extensions]="extensions" [content]="content" (editorCreated)="editor.set($event)"/>The Angular toolbar auto-renders the font family dropdown with a dynamic label, font previews, and active state highlighting.
import { Domternal } from '@domternal/react';import { Document, Paragraph, Text, FontFamily } from '@domternal/core';
export default function Editor() { return ( <Domternal extensions={[Document, Paragraph, Text, FontFamily]} content="<p>Select text and pick a font from the toolbar dropdown.</p>" > <Domternal.Toolbar /> <Domternal.Content /> </Domternal> );}import { Editor, Document, Paragraph, Text, FontFamily } from '@domternal/core';
const editor = new Editor({ element: document.getElementById('editor')!, extensions: [Document, Paragraph, Text, FontFamily],});
// Set a specific fonteditor.commands.setFontFamily('Georgia');
// Remove font (reset to default)editor.commands.unsetFontFamily();
// Check if a specific font is activeeditor.isActive('textStyle', { fontFamily: 'Georgia' }); // true/falseFontFamily works identically without a theme. Build your own font picker UI and call the commands programmatically.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
fontFamilies | string[] | 8 default fonts | Font names shown in the toolbar dropdown. Commands accept any font regardless of this list. |
Default fonts
Section titled “Default fonts”The default list includes 8 typefaces covering sans-serif, serif, and monospace:
| Font | Category |
|---|---|
| Arial | Sans-serif |
| Verdana | Sans-serif |
| Tahoma | Sans-serif |
| Trebuchet MS | Sans-serif |
| Times New Roman | Serif |
| Georgia | Serif |
| Palatino Linotype | Serif |
| Courier New | Monospace |
Custom fonts
Section titled “Custom fonts”FontFamily.configure({ fontFamilies: ['Inter', 'Merriweather', 'Fira Code'],})Empty list
Section titled “Empty list”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 onlyCommands
Section titled “Commands”setFontFamily
Section titled “setFontFamily”Sets the font family on the current selection. Accepts any font family name as a string.
editor.commands.setFontFamily('Georgia');
// With chainingeditor.chain().focus().setFontFamily('Courier New').run();Under the hood, this calls setMark('textStyle', { fontFamily }) to apply the font attribute on the TextStyle carrier mark.
unsetFontFamily
Section titled “unsetFontFamily”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();Keyboard shortcuts
Section titled “Keyboard shortcuts”FontFamily does not register any keyboard shortcuts.
Input rules
Section titled “Input rules”FontFamily does not register any input rules.
Toolbar items
Section titled “Toolbar items”FontFamily registers a dropdown with dynamicLabel in the toolbar.
| Dropdown | Icon | Group | Priority | Display mode |
|---|---|---|---|---|
fontFamily | textAa | textStyle | 150 | text |
Dynamic label
Section titled “Dynamic label”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 position | Trigger shows |
|---|---|
Text with font-family: Georgia | Georgia |
Text with font-family: 'Courier New' | Courier New |
| Text with no explicit font | Aa icon (fallback) |
| Text with custom font not in list | Font name from inline style |
The label resolution follows this order:
- If a dropdown item is active (cursor in text matching a configured font), show that item’s label
- Otherwise, read the inline
font-familystyle at the cursor position (handles custom fonts not in the list) - If no inline style found, show the
textAaicon as fallback
Dropdown items
Section titled “Dropdown items”Each font in the fontFamilies array becomes a dropdown item:
| Property | Value |
|---|---|
name | fontFamily-{name} (e.g., fontFamily-Georgia) |
command | setFontFamily |
commandArgs | [fontName] |
isActive | { name: 'textStyle', attributes: { fontFamily: name } } |
icon | textAa |
label | Font name (e.g., Georgia) |
style | font-family: {name} (renders the item in its own font) |
priority | 200 - 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.
Trigger width
Section titled “Trigger width”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”.
How it works
Section titled “How it works”Carrier mark pattern
Section titled “Carrier mark pattern”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>Quote handling
Section titled “Quote handling”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.
Automatic dependency
Section titled “Automatic dependency”FontFamily declares TextStyle as both a dependency (dependencies: ['textStyle']) and includes it via addExtensions(). You do not need to add TextStyle separately.
Empty mark cleanup
Section titled “Empty mark cleanup”When you call unsetFontFamily(), it:
- Sets the
fontFamilyattribute tonullviasetMark('textStyle', { fontFamily: null }) - Calls
removeEmptyTextStyle()to check if the TextStyle mark has any remaining non-null attributes - If all attributes are
null(no font-family, no color, no font-size, no background-color), removes the<span>wrapper entirely
HTML rendering
Section titled “HTML rendering”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 textNo validation
Section titled “No validation”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.
Exports
Section titled “Exports”import { FontFamily } from '@domternal/core';import type { FontFamilyOptions } from '@domternal/core';| Export | Type | Description |
|---|---|---|
FontFamily | Extension | The font family extension |
FontFamilyOptions | TypeScript type | Options for FontFamily.configure() |
Source
Section titled “Source”@domternal/core - FontFamily.ts