Headless text markup
The instance.annotations.textMarkup namespace lets you create text markup annotations, highlights, underlines, strikeouts, and squigglies without going through the default text selection toolbar. Use it from a custom inline toolbar, a keyboard shortcut your application defines, or any other UI you want to layer over the viewer.
Looking for the visual side of this? See the supported slots reference for replacing the inline toolbar that appears when the user selects text. This page covers the programmatic surface you’ll call from inside that custom UI.
When to use this
Reach for the headless text markup API when you’re building:
- A custom inline toolbar that floats near the text selection with your own styling.
- A keyboard shortcut your application defines that highlights the current selection.
- A “highlight all matches” workflow that combines
searchresults withcreateFromCurrentTextSelection. - A custom action driven by a remote command from a multiuser collaboration layer.
API reference
| Method | Notes |
|---|---|
instance.annotations.textMarkup.createFromCurrentTextSelection(type) | Creates markup annotations of type over the current text selection. type is one of 'highlight', 'underline', 'strikeout', 'squiggly'. Throws if no text is currently selected. |
instance.annotations.textMarkup.enterHighlighterMode(options?) | Enters continuous text-highlighter mode (text-highlighter) so subsequent text selections are highlighted automatically. Pass { presetPatch } to merge values into the highlight preset before activation. |
instance.annotations.textMarkup.getColorPresets() | Returns the resolved color presets for markup annotations, separated by highlight and markup. |
createFromCurrentTextSelection returns a list of the created annotations. Because it produces one annotation per page that the selection spans, the list can contain more than one entry.
Example: A custom inline markup toolbar
This example renders a minimal floating toolbar above the user’s text selection. Each button creates a different markup type for the selected text:
const instance = await NutrientViewer.load({ container: "#viewer", document: "contract.pdf"});
const toolbar = document.getElementById("markup-toolbar");
instance.addEventListener("textSelection.change", (selection) => { // The event emits either a `TextSelection` or `null`. A null check is enough. if (!selection) { toolbar.style.display = "none"; return; }
toolbar.style.display = "flex";});
function markup(type) { return () => { instance.annotations.textMarkup.createFromCurrentTextSelection(type); };}
toolbar.querySelector("#highlight").onclick = markup("highlight");toolbar.querySelector("#underline").onclick = markup("underline");toolbar.querySelector("#strikeout").onclick = markup("strikeout");toolbar.querySelector("#squiggly").onclick = markup("squiggly");The created annotations follow the current preset for the chosen type. To create them with a specific color or opacity, update the highlight preset first and then create from the selection. setCurrentAnnotationPreset only switches which preset is active. To change a preset’s value, use setAnnotationPresets with the callback form so you merge into the existing preset map:
instance.setAnnotationPresets((presets) => ({ ...presets, highlight: { ...presets.highlight, color: NutrientViewer.Color.fromHex("#FFEB3B") }}));instance.setCurrentAnnotationPreset("highlight");
instance.annotations.textMarkup.createFromCurrentTextSelection("highlight");Example: Matching the default color presets
Render a color picker that reuses the swatches from the default markup toolbar. getColorPresets() returns two entries — use highlight for the highlight preset, and markup for the underline, strikeout, and squiggly presets:
const presets = instance.annotations.textMarkup.getColorPresets();
const palette = document.getElementById("markup-color-palette");presets.highlight.presets.forEach((preset) => { const swatch = document.createElement("button"); swatch.style.backgroundColor = preset.color.toHex(); swatch.onclick = () => { instance.setAnnotationPresets((presets) => ({ ...presets, highlight: { ...presets.highlight, color: preset.color } })); instance.setCurrentAnnotationPreset("highlight"); }; palette.appendChild(swatch);});See the color presets guide for the full cross-namespace pattern.
Related
- Color presets — The cross-namespace pattern for reading preset colors.
- Redactions from selection — The same selection-based pattern for redactions.