ClickorKeyboard shortcut Alt + L

Dragto resize

Nord Design System SearchDeveloperDeveloperGetting startedUsing Web ComponentsWebfontsCDNLocalizationCSS Framework Legacy ESLint PluginWorking with AIFAQDesignDesignGetting startedFoundationsThemesBrand assetsToolsComponentsComponentsAccordion New Aside New Autocomplete New AvatarBadgeBanner Updated ButtonButton GroupCalendar Updated Card Updated Chart New Checkbox Updated Collapsible New Combobox New Command MenuDate Picker Updated Date Range Picker New DividerDrawer Updated DropdownEmpty StateField New FieldsetFilter Bar New FooterHeaderIconInput Updated Item New Kbd New LayoutMessageMeter New Modal Updated NavigationNotificationNumber Field New Otp Field New Outline New Pagination New Performance FixturePopout Updated ProgressProgress BarQrcodeRadio Updated Range Updated Rich Text Editor New Scroll Area New Segmented ControlSelect Updated SkeletonSpinnerStackTabTableTagTextarea Updated Time Picker New ToastToggle Updated TooltipTop BarTruncate New Visually HiddenDesign TokensDesign TokensTailwind CSSTailwind CSSBlocksBlocksTemplatesTemplatesIconsIconsPlaygroundPlaygroundLatest UpdatesLatest UpdatesChangelogChangelogMigration guidesMigration guides
GitHub

Clickto expandKeyboard shortcut Alt + L

RichTextEditor New Alpha

Open in Storybook

Lets users create structured, formatted HTML content with an accessible editing toolbar.

This component is considered alpha. We're still finalising the API, so it may include a breaking change at any time — use it at your own risk.
Loading...

Usage

Rich Text Editor lets people create structured HTML for clinical notes, email and document templates, instructions, and other content that needs more formatting than a Textarea provides. Its Nord toolbar supports inline text styles, headings, lists, indentation, horizontal rules, tables, colours, undo and redo.

Rich Text Editor uses Tiptap as its editing engine. Nord owns the component API, toolbar composition, accessibility behavior and HTML compatibility contract, so applications do not need to interact with Tiptap directly.

The editor is an opt-in package entry because Tiptap and ProseMirror are larger than typical Nord components. Import it explicitly in applications that use rich text:

import "@nordhealth/components/lib/RichTextEditor"

Rich Text Editor renders its built-in label, hint and error on its own. Wrapped in a Field, the Field takes over with a Field Label, Field Description and Field Error, and the built-in versions step aside automatically.

The value is canonical HTML. Setting it updates the document without firing input or change; user edits fire input, followed by change when focus leaves the editor.

Composition

Rich Text Editor owns the value, form behavior and Tiptap document. Compose its public parts when a task needs a specific toolbar or toolbar placement. If the Toolbar or Content parts are omitted, the editor renders its standard toolbar preset and editable surface automatically.

RichTextEditor
├── RichTextEditorToolbar           (optional; replaces the preset)
│   ├── RichTextEditorToolbarGroup  (optional grouping)
│   │   └── RichTextEditorCommand
│   └── Application controls        (optional)
└── RichTextEditorContent           (optional; implicit when omitted)
<nord-rich-text-editor label="Visit summary">
  <nord-rich-text-editor-toolbar>
    <nord-rich-text-editor-toolbar-group label="Text formatting">
      <nord-rich-text-editor-command command="bold"></nord-rich-text-editor-command>
      <nord-rich-text-editor-command command="italic"></nord-rich-text-editor-command>
    </nord-rich-text-editor-toolbar-group>
  </nord-rich-text-editor-toolbar>
  <nord-rich-text-editor-content></nord-rich-text-editor-content>
</nord-rich-text-editor>

Rich Text Editor Content

Rich Text Editor Content provides the editable document surface. Put it after the Toolbar for the conventional layout, or before the Toolbar to place controls below the document. Omit it to use the implicit surface after the toolbar.

Rich Text Editor Toolbar

Rich Text Editor Toolbar holds formatting commands and application-owned controls. A nested Toolbar replaces the toolbar preset and provides the complete keyboard interaction model, including Alt+F10 and roving arrow-key navigation.

Rich Text Editor Toolbar Group

Rich Text Editor Toolbar Group gives related commands an accessible group label and keeps their visual spacing consistent.

Rich Text Editor Command

Rich Text Editor Command connects a Nord-owned command and optional value to its nearest editor. It keeps command behavior, active state, localization and disabled state connected without exposing Tiptap.

Examples

Standalone or inside a Field

Use the editor on its own with its built-in label, hint and error, or wrap it in a Field so the Field provides the labelling. Both render the same editor:

InlineWith Field

Compose a toolbar

Choose, group and order only the controls the task needs. The nested toolbar takes precedence over the toolbar preset.

Use value for commands that need an option, and render them as menu items inside a Dropdown:

<nord-dropdown size="s">
  <nord-button slot="toggle" type="button" size="s">Text colour</nord-button>
  <nord-rich-text-editor-command
    variant="menu-item"
    command="text-color"
    value="#0063a3"
    label="Blue"
  >Blue</nord-rich-text-editor-command>
</nord-dropdown>

Available commands are:

  • Text: bold, italic, underline, strike, subscript, superscript and clear-formatting.
  • Structure: bullet-list, ordered-list, indent, outdent, horizontal-rule, paragraph-format, undo and redo.
  • Text styles: font-family, font-size, text-color and background-color. Supply the chosen option with value.
  • Tables: table. It renders the complete Nord dropdown for inserting and editing tables; individual table actions are internal.

Application controls and templates

Place application-owned controls directly in the composed toolbar. Nord buttons, dropdowns and native form controls join the same arrow-key navigation as editor commands. Call insertContent() to insert content at the preserved selection. The options specify format: "html" | "text", whether an active selection is replaced, and whether focus returns to the document. Active selections are replaced and focus is restored by default. Pass { replace: true } to replace the complete document as one undoable action. In this example the Content component comes first, placing the toolbar below the editable surface.

Insert patient name

Toolbar presets

The default full toolbar covers the formatting used by legacy Froala fields. Use toolbar="compact" for text styles, clear formatting, undo and redo, or toolbar="none" when no toolbar is needed. Presets are convenience compositions built from the same public toolbar and command components.

Hint placement

Like other Nord data-entry components, Rich Text Editor shows hint text below the label by default. Set hint-below when the guidance should follow the editor and any error message instead.

Character limit and resizing

Set maxlength to limit user input by grapheme characters and add character-counter to show the current count. Existing controlled content that is already over the limit remains editable so users can shorten it.

The default resize="vertical" lets users drag the lower edge. Set resize="auto" to grow the editable surface with its content instead.

Pasting content

Pasting is plain text by default, which avoids carrying styles from external documents. Set paste-mode="formatted" when supported headings, lists, tables and inline styles should be preserved. In either mode, pasted HTML is filtered through the editor schema.

<nord-rich-text-editor
  label="Email template"
  paste-mode="formatted"
></nord-rich-text-editor>

Controlled HTML values

Read and write HTML through value. Listen to input for live synchronization and change for a committed edit. Programmatic assignments do not emit either event.

const editor = document.querySelector("nord-rich-text-editor")

editor.value = "<p>Patient is recovering well.</p>"
editor.addEventListener("input", () => {
  saveDraft(editor.value)
})

The editor canonicalizes content through its schema before exposing or submitting it. Continue to validate and sanitize untrusted HTML at the application boundary, especially before rendering stored content outside the editor.

Autosaving

Rich Text Editor does not send or schedule saves itself because persistence and retry behavior belong to the application. Use input to trigger an existing autosave mechanism. The value property and the form-associated HTML value are both synchronized before input is dispatched.

const form = document.querySelector("form")
const editor = form.querySelector("nord-rich-text-editor")

editor.addEventListener("input", () => {
  queueAutosave({
    html: editor.value,
    formValue: new FormData(form).get(editor.name),
  })
})

Existing media

Data images used by label and QR templates are supported. Set media-origin to preserve existing HTTP or HTTPS images from one configured origin; remote images from other origins are removed.

<nord-rich-text-editor
  label="Label template"
  media-origin="https://media.example.com"
></nord-rich-text-editor>

Legacy Froala content

The schema preserves supported legacy content, including headings, paragraphs and empty paragraphs, blockquotes, list indentation, horizontal rules, tables, Froala table classes, column widths, cell background colours, label images and QR SVG. Scripts, iframes, event-handler attributes and unsupported remote media are removed.

Read-only review and rendered output

For an in-product read-only review, keep the value in the component and combine readonly with toolbar="none". The document remains focusable and submitted with its form while headings, paragraphs, lists, blockquotes, tables, images and QR SVG use the same Nord-token styles as the editable view.

<nord-rich-text-editor
  label="Saved clinical notes"
  name="clinical_notes"
  readonly
  toolbar="none"
></nord-rich-text-editor>

HTML rendered outside the component, including email, PDF and label output, does not inherit shadow-DOM styles. Sanitize it on the backend, retain the canonical rich-text-editor-table class during rendering, and apply the application’s audited output stylesheet. Transitional fr-* classes remain only for migration-era renderers.

Forms and validation

Add name to include the editor HTML in FormData. The editor supports form reset, disabled fieldsets, required, maxlength, checkValidity() and reportValidity(). Read-only content stays focusable and is submitted; disabled content is omitted.

<form>
  <nord-rich-text-editor
    label="Discharge instructions"
    name="discharge_instructions"
    required
  ></nord-rich-text-editor>
  <nord-button type="submit" variant="primary">Save</nord-button>
</form>

Narrow layouts

The toolbar wraps at narrow inline sizes without causing page overflow. Keep the editor container wide enough for readable document content when possible.

RTL

Rich Text Editor follows the document or container direction. The toolbar order and arrow-key navigation mirror in right-to-left layouts.

Accessibility

  • Always provide an accessible name with the built-in label or a Field Label connected with for.
  • Press Alt+F10 from the document to move to the toolbar. Use arrow keys, Home and End between controls, and Escape or Tab to return to the document.
  • Use error or a Field Error to communicate validation; the message is associated with the editor and is not conveyed by colour alone.
  • Use readonly when content should remain readable, focusable and included in form submission. Use disabled only when the content and control are unavailable.
  • Give every application control in a composed toolbar clear text or an accessible label. It becomes part of the toolbar's keyboard order.
  • The character counter announces the remaining count near the limit, while maxlength exposes the corresponding form validity state.
  • Keep the default plain-text paste mode unless preserving supported document formatting is necessary for the task.

Verification status

Automated coverage includes Axe checks for basic, required/error, readonly, disabled and RTL composed-toolbar states. Browser tests also cover keyboard commands, 320 CSS pixel reflow at 200% text, RTL navigation, and minimum 44 by 44 CSS pixel touch targets. Visual snapshots cover Nord and Vet light/dark themes, forced colours, editor states, long content, legacy content and narrow layouts.

Manual keyboard, NVDA, VoiceOver, system high-contrast/forced-colour, 200% text, 400% browser zoom, RTL and touch-device checks are required before the component can move beyond Alpha. Automated emulation is not a substitute for those checks.

API reference

RichTextEditor

Rich text editor lets users create structured, formatted HTML content.

<nord-rich-text-editor></nord-rich-text-editor>

Props

PropertyAttribute Description TypeDefault
toolbartoolbarControls which legacy-compatible formatting controls are shown.ToolbarPreset'full'
mediaOriginmedia-originOptional origin from which existing media images may be preserved.string | undefined
placeholderplaceholderPlaceholder text shown when the document is empty.string | undefined
pasteModepaste-modeControls whether pasted content keeps schema-supported formatting.PasteMode'plain'
resizeresizeControls whether the editable surface can be resized vertically or grows automatically.'vertical' | 'auto''vertical'
maxLengthmaxlengthControls the maximum number of plain-text grapheme characters users can enter.number | undefined
characterCountercharacter-counterControls whether a plain-text grapheme character count is shown.booleanfalse
sizesizeThe size of the component.'s' | 'm' | 'l''m'
requiredrequiredDetermines whether the control is required or not. A required control is announced as such to assistive technology and, inside a <nord-field>, drives the required indicator on the <nord-field-label>. When using this property you need to also set “novalidate” attribute on a form element to prevent browser from displaying its own validation errors.booleanfalse
readonlyreadonlyMakes the component readonly, so that it is not editable. Readonly differs from disabled in that readonly fields are still focusable and will be submitted with a form.booleanfalse
disableddisabledMakes the component disabled. This prevents users from being able to interact with the component, and conveys its inactive state to assistive technologies.booleanfalse
namenameThe name of the form component.string | undefined
valuevalueThe value of the form component.string''
formformGets the form, if any, associated with the form element. The setter accepts a string, which is the id of the form.HTMLFormElement | null
Field properties
PropertyAttribute Description TypeDefault
labellabelLabel for the control. Ignored when the control is wrapped in a <nord-field>, which provides the label via <nord-field-label>.string''
hinthintOptional hint text shown with the control. Ignored inside a <nord-field>, which provides it via <nord-field-description>.string | undefined
hintBelowhint-belowRenders the hint below the control and any error instead of below the label.booleanfalse
hideLabelhide-labelVisually hide the label, but still expose it to assistive technologies.booleanfalse
errorerrorOptional error shown with the control. Ignored inside a <nord-field>, which provides it via <nord-field-error>.string | undefined
hideRequiredhide-requiredVisually hide the required indicator, but still expose the required state to assistive technologies.booleanfalse

Slots

Slot name Description
labelUse when a label requires more than plain text.
hintOptional slot that holds hint text for the editor.
errorOptional slot that holds error text for the editor.
Default slotOptional Rich Text Editor Content and Toolbar composition.
additional-controlsOptional application-owned controls shown in the toolbar.

Methods

Method nameParameters Description
checkValidity() => booleanN/AReturns whether the editor satisfies its validation constraints.
reportValidity() => booleanN/AReports validation errors and returns whether the editor is valid.
focus(options?: FocusOptions) => voidoptions: FocusOptionsProgrammatically move focus to the component.
blur() => voidN/AProgrammatically remove focus from the component.
click() => voidN/AProgrammatically simulates a click on the component.
insertContent(content: string, options: RichTextEditorInsertContentOptions) => booleancontent: string
options: RichTextEditorInsertContentOptions
Inserts schema-limited HTML or literal text at the current selection. By default an active selection is replaced and focus returns to the editor. Pass replace: true to replace the complete document as one undoable action.
EventDetail TypeDescription
inputNordEventFired as the user edits content or applies an editor command.
changeNordEventFired when focus leaves the editor after its value changed.

CSS Properties

CSS Custom Properties provide more fine grain control over component presentation. We advise utilizing existing properties on the component before using these.

PropertyDescriptionDefault
--n-rich-text-editor-inline-sizeControls the inline size of the editor.100%
--n-rich-text-editor-block-sizeControls the minimum block size of the editable surface.160px
--n-rich-text-editor-max-block-sizeControls the maximum block size of the editable surface.500px
--n-rich-text-editor-backgroundControls the editor background.var(--n-color-surface)
--n-rich-text-editor-colorControls the editor text color.var(--n-color-text)
--n-rich-text-editor-border-colorControls the editor border color.var(--n-color-border-strong)

Parts

This component is made up of the following parts.

Rich Text Editor Command

Command renders one formatting control for the nearest Rich Text Editor.

<nord-rich-text-editor-command></nord-rich-text-editor-command>

Props

PropertyAttribute Description TypeDefault
commandcommandThe Nord-owned formatting control to render.Command | undefined
labellabelOptional accessible label that overrides the localized command label.string | undefined
valuevalueOptional serializable value used by parameterized commands.string | undefined
variantvariantRenders the command as a toolbar button or a dropdown item.'button' | 'menu-item''button'

Methods

Method nameParameters Description
focus(options?: FocusOptions) => voidoptions: FocusOptions
click() => voidN/A

Rich Text Editor Content

Content provides the editable surface within a composed Rich Text Editor. Place it before or after a Rich Text Editor Toolbar to control the visual order.

<nord-rich-text-editor-content></nord-rich-text-editor-content>

Rich Text Editor Toolbar

Toolbar composes formatting commands and application controls for a Rich Text Editor.

<nord-rich-text-editor-toolbar></nord-rich-text-editor-toolbar>

Props

PropertyAttribute Description TypeDefault
labellabelAccessible label for the toolbar. Defaults to the editor's localized label.string | undefined

Slots

Slot name Description
Default slotRich text command groups and application controls.

Rich Text Editor Toolbar Group

Toolbar Group groups related Rich Text Editor commands.

<nord-rich-text-editor-toolbar-group></nord-rich-text-editor-toolbar-group>

Props

PropertyAttribute Description TypeDefault
labellabelAccessible label describing the related commands.string''

Slots

Slot name Description
Default slotRelated Rich Text Editor commands.