Skip to content

API Reference

Jace edited this page Jun 6, 2026 · 1 revision

API Reference

Every export of @highlighters/core and its framework bindings, with signatures and defaults. Ground-truth: nothing here is invented. For prose explanations of each behaviour see the topic pages; for the full option catalogue with ranges and effects see Options-Reference.

Accuracy note. Some framework JSDoc examples in source show options={{ preset: "wet", color: "pink" }}. There is no preset option and no named-color shorthand in the actual API. HighlightOptions has no preset field, and color is a CSS color string or a { palette, swatch } object (a bare "pink" is passed through as a literal CSS color, not a palette lookup). Treat those snippets as illustrative only; the real fields are below.

Every per-mark random value derives from a seed, never the wall clock, so identical inputs produce byte-identical marks on server and client. See How-It-Works and SSR-Support.


Packages and entry points

Import Contents DOM?
@highlighters/core Full API: render entry points, config/palette helpers, geometry builders, targeting, tier selection, all types. Yes
@highlighters/core/path DOM-free, SSR-safe subset: config/palette helpers, pure geometry builders, RNG, pure types. No render/* or targeting/*. No
@highlighters/react Highlight component, useHighlight hook, re-exported core types. Yes
@highlighters/vue Highlight component, useHighlight composable, re-exported core types. Yes
@highlighters/svelte highlight action, re-exported core types. Yes

Picking an entry point: Which-API-Should-I-Use.


Render entry points (@highlighters/core)

highlight(target, options?, host?)

Primary entry point. Highlights any target.

import { highlight } from "@highlighters/core";

const mark = highlight("#intro p", { markType: "highlight", color: "#f5e6a8" });
mark.hide();
mark.show();
mark.remove();

Parameters: target: Target, options?: HighlightOptions, host?: HTMLElement | null Returns: MarkHandle

  • host is an optional positioned element to mount the overlay inside (for transformed, scrolling, or stacked containers). It is promoted to position: relative if static. Defaults to the document body.
  • Default snap is derived from the target shape: element/selector to "line", Range/Selection/text query to "word".
  • Returns an inert no-op handle when there is no DOM, or when the target resolves to zero ranges.

highlightAll(options?)

Highlights whole-page and declarative content. Collects all [data-highlight] elements plus a page scan rooted at document.body (honouring exclusions), then attaches a debounced MutationObserver so added nodes get marked and removed nodes drop their marks without a full rescan. One handle covers all matches. See Page-Highlighting.

import { highlightAll } from "@highlighters/core";

const page = highlightAll({ palette: "mild" });

Returns: MarkHandle

  • Default snap is "line".
  • Returns an inert handle outside a DOM. With no matches yet, it still wires the watcher so a later DOM change produces a mark.
  • The watcher's disconnect folds into the returned handle's remove().

highlightSelection(options?)

Highlights the user's live selection in real time, driven by selectionchange. See Selection-Highlighting.

import { highlightSelection } from "@highlighters/core";

const live = highlightSelection({ speed: { enabled: true } });

Returns: MarkHandle

  • Default snap is "word".
  • On coarse pointers (touch) it returns an inert handle and defers to native selection UI (no overlay).
  • A backward drag (focus before anchor) pours ink from the right edge.
  • When the selection empties it fades out over 200ms then drops the bands (gated by fadeOnClear; instant under reduced-motion). Re-selecting cancels the fade.
  • Speed-aware ink (the speed group) engages here only, and only during a primary-button fine-pointer drag. It is suppressed under prefers-reduced-motion and is a no-op for programmatic/keyboard/static selections or when speed.enabled is false. See Ink-and-Optics.
  • update(opts) composes additively across calls (options accumulate via mergeOptions).
  • remove() detaches the selectionchange, pointer, and tracker listeners.
  • The tier getter returns the live renderer's tier, or "css" before first mount.

group(handles)

Bundles handles for sequential show/hide choreography. show() reveals members in array order so the draw-on staggers like a pen down the page. See Animation.

import { group, highlight } from "@highlighters/core";

const g = group([highlight("#a"), highlight("#b")]);
g.show();

Parameters: handles: MarkHandle[] Returns: GroupHandle


MarkHandle

A handle to a single mark. remove() restores the pre-highlight DOM; update() re-resolves options without re-seeding stable geometry.

interface MarkHandle {
  show(): void;       // Reveal the mark (re-animates only on first show or explicit re-show).
  hide(): void;       // Hide without tearing down geometry or observers.
  update(opts: Partial<HighlightOptions>): void; // Merge over current config and re-render.
  remove(): void;     // Remove the mark, restore the DOM, disconnect observers.
  isShowing(): boolean;
  readonly tier: RendererTier; // The concrete renderer tier in use.
}

GroupHandle

interface GroupHandle {
  show(): void;   // Show all members, staggered in array order for sequential draw-on.
  hide(): void;
  remove(): void; // Remove all members and restore the DOM.
  readonly marks: MarkHandle[]; // Member handles, in choreography order.
}

Targeting types

Target

type Target = Element | string | Range | Selection | TextTarget | PageTarget;
Variant Meaning
Element Highlights its text.
string A CSS selector.
Range A DOM range.
Selection A DOM selection.
TextTarget A text query.
PageTarget A page or sub-tree with include/exclude.

TextTarget

interface TextTarget {
  text: string | RegExp;     // Every match within root, including matches spanning inline boundaries.
  root?: Element | Document; // Defaults to document.body.
}

PageTarget

interface PageTarget {
  root?: Element | Document; // Root to scan. Defaults to document.body.
  include?: string[];        // Selectors whose subtrees are additionally included.
  exclude?: string[];        // Selectors whose subtrees are excluded; precedence over inclusion.
}

Exclusion always takes precedence over inclusion at every level. Nodes inside any subtree matching an exclude selector, or carrying the data-highlight-exclude attribute, are skipped.


HighlightOptions

All fields are optional; unset fields fall back to DEFAULT_OPTIONS. This is the signature only; for ranges, units, and the visual effect of each field see Options-Reference.

interface HighlightOptions {
  shape?: ShapeType;                 // Synonym of markType.
  markType?: MarkType;               // "highlight" (default) | "underline" | "overline" | "strike-through"
  color?: ColorValue | PaletteSwatch;// CSS color string, or { palette, swatch }. Default "#f5e6a8".
  palette?: PaletteName;             // Draws the default swatch when color is unset.
  gradient?: GradientConfig | null;  // Multi-stop gradient; overrides color when present.
  opacity?: number;                  // 0-1 (clamped). Default 0.55.
  blendMode?: BlendMode;             // Default "multiply".
  tip?: TipOptions;                  // Nib geometry.
  ink?: InkOptions;                  // Ink behaviour.
  speed?: SpeedDynamicsOptions;      // Speed-aware deposit (live selection only; Beta).
  edge?: EdgeOptions;                // Edge waviness/roughness/cap/radius.
  paper?: PaperOptions;              // Paper surface.
  glow?: GlowOptions;                // Additive fluorescence.
  snap?: SnapMode;                   // Default per entry point (see above).
  fadeOnClear?: boolean;             // Live-selection only. Default true.
  seed?: number | null;              // Explicit deterministic seed; derived from target identity when omitted.
  renderer?: RendererTierPreference; // Default "auto".
  animation?: AnimationOptions;      // Entrance animation.
  semantic?: boolean;                // Wrap each run in a real <mark>. Default false. Reversible by remove().
  contrastBackground?: ColorValue | null; // Drives only the dev-time WCAG warning; not rendered.
}

shape and markType are synonyms that collapse onto markType during merge (override wins, then override.shape, then base). ColorValue = string (hex, rgb(), hsl(), named, currentColor, or var(...)).

Nested option groups

interface TipOptions {            // See [[Tips-and-Edges]]
  type?: TipType;                 // "chisel" (default) | "bullet" | "fine"
  width?: number;                 // Reserved: not consumed by the renderer.
  thickness?: number;             // Reserved: not consumed by the renderer.
  angle?: number;                 // Chisel slant, degrees. Default 35.
  overshoot?: number;             // Signed px each outer end runs past the text edge. Default 2.
  overshootJitter?: number;       // Per-end deterministic variance (>=0). Default 1.
  angleJitter?: number;           // Per-line deterministic angle variance (>=0). Default 0.
}

interface InkOptions {            // 0-1 unless noted. See [[Ink-and-Optics]]
  flow?: number;                  // Default 0.45.
  viscosity?: number;             // Default 0.5.
  feathering?: number;            // Default 0.2.
  streakiness?: number;           // Default 0.25.
  dryout?: number;                // Default 0.1.
  startEndBuildup?: number;       // -1 to 1. Default 0.1.
  flowFade?: number;              // Default 0.5.
}

interface SpeedDynamicsOptions {  // Beta, live-selection only. See [[Ink-and-Optics]]
  enabled?: boolean;              // Default false.
  sensitivity?: number;          // 0-1. Default 1.
  slowSpeed?: number;             // px/ms (>=0). Default 2.5.
  fastSpeed?: number;             // px/ms (>=0); clamped >= slowSpeed. Default 10.5.
  minDeposit?: number;            // 0-1. Default 0.4.
  smoothing?: number;             // 0-1. Default 1.
  resolution?: number;            // Clamped 4-24, rounded. Default 24.
  dryoutBoost?: number;           // 0-1. Default 1.
  streakBoost?: number;           // 0-1. Default 0.08.
  featherReduce?: number;         // 0-1. Default 1.
  poolBoost?: number;             // 0-1. Default 1.
}

interface EdgeOptions {           // See [[Tips-and-Edges]]
  waviness?: number;              // Peak displacement, px. Default 1.
  frequency?: number;             // Wave grid segment length, px. Default 22.
  roughness?: number;             // 0-1 micro-jitter. Default 0.2.
  cap?: EdgeCap;                  // "round" (default) | "flat" | "square"
  radius?: number;                // Corner radius, px. Default 5.
}

interface PaperOptions {
  absorbency?: number;            // 0-1. Default 0.3.
}

interface GlowOptions {           // Off by default. See [[Ink-and-Optics]]
  enabled?: boolean;              // Default false.
  intensity?: number;             // 0-1. Default 0.5.
  spread?: number;                // px. Default 4.
  color?: ColorValue;             // "" resolves to a brightened form of the ink color. Default "".
}

interface AnimationOptions {      // Suppressed under prefers-reduced-motion. See [[Animation]]
  draw?: boolean;                 // Default true.
  duration?: number;              // ms (positive). Default 420.
  easing?: EasingValue;           // Default "ease-out".
  direction?: AnimationDirection; // Default "left-to-right".
  stagger?: number;               // Per-line/per-mark delay, ms. Default 90.
  trigger?: AnimationTrigger;     // "immediate" (default) | "in-view"
  threshold?: number;             // 0-1 IntersectionObserver threshold. Default 0.2.
  rootMargin?: string;            // IntersectionObserver root margin. Default "0px".
  repeat?: boolean;               // Re-animate on each view entry. Default false.
}

GradientConfig / GradientStop

interface GradientConfig {
  type: "linear";
  angle?: number;        // CSS degrees. Defaults to 85.
  stops: GradientStop[]; // Two or more for a visible gradient.
}
interface GradientStop {
  offset: number;        // 0 (start) to 1 (end).
  color: ColorValue;
  opacity?: number;      // 0-1. Defaults to 1.
}

Enums and string-union types

Type Values
MarkType / ShapeType "highlight" | "underline" | "overline" | "strike-through"
TipType "chisel" | "bullet" | "fine"
EdgeCap "flat" | "round" | "square"
BlendMode "multiply" | "normal" | "darken" | "screen" | "overlay" | "color-burn"
SnapMode "none" | "word" | "line" | "glyph"
RendererTierPreference "auto" | "svg" | "css" | "highlight-api"
RendererTier "svg" | "css" | "highlight-api"
AnimationDirection "left-to-right" | "right-to-left" | "center-out"
AnimationTrigger "immediate" | "in-view"
EasingValue "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out" | (string & {})
PaletteName "fluorescent" | "mild" | "vintage" | "neutral" | "calm"
ColorValue string

See Mark-Types-and-Shapes and Snapping-and-Overshoot for what these control.


Palette helpers

There are no presets. Color coordination is via palette families (default family mild, default color mild to yellow = #f5e6a8). Each palette's swatches map is ordered, and that order is the color-coding cycle. For the full swatch tables see Color-and-Palettes.

const PALETTES: Record<PaletteName, Palette>            // All palette families (data).
function getPalette(name: PaletteName): Palette         // Throws on unknown family.
function resolveSwatch(ref: PaletteSwatch): ColorValue  // Throws on unknown swatch.
function defaultSwatch(name: PaletteName): ColorValue    // Default color for a family.

interface PaletteSwatch { palette: PaletteName; swatch: string; }
interface Palette { name: PaletteName; swatches: Record<string, ColorValue>; }

Using a palette: pass { color: { palette: "mild", swatch: "pink" } }, or { palette: "mild" } to use that family's default swatch.


Renderer tiers

Three tiers behind one API. Degrade is fidelity-only: a lower tier never moves or recolours a mark, only simplifies edge organicness and texture. See Performance.

Tier (RendererTier) Constructor Requires
"svg" (highest, default) createSvgRenderer() clip-path, mask-image, SVG filters (SVGFETurbulenceElement)
"css" (auto-degrade floor) createCssRenderer() mix-blend-mode, box-decoration-break: clone
"highlight-api" createHighlightApiRenderer() CSS Custom Highlight API (CSS.highlights + Highlight)

Tier-selection functions

const DEFAULT_DEGRADE_THRESHOLD = 50;

function detectEnvironment(): RenderEnvironment   // Feature-detect + read motion/data/pointer prefs. SSR-safe.
function selectTier(
  requested: RendererTierPreference,
  env: RenderEnvironment,
  markCount: number,                              // Simultaneously visible marks.
): RendererTier

With renderer: "auto", selection starts from the highest supported tier in svg -> css -> highlight-api order. If the chosen tier is svg, it degrades to css under prefers-reduced-motion: reduce, prefers-reduced-data: reduce, or a mark count above DEFAULT_DEGRADE_THRESHOLD (50). css is the floor of auto-degrade; highlight-api is auto-chosen only if it is the highest supported tier. When renderer is pinned, the request is honoured if supported, else it steps down to the nearest supported tier (final fallback "css").

interface RenderEnvironment {
  supportsSvgFilters: boolean;   // Tier A
  supportsCssBlend: boolean;     // Tier B
  supportsHighlightApi: boolean; // Tier C
  prefersReducedMotion: boolean;
  prefersReducedData: boolean;
  coarsePointer: boolean;        // touch; gates live-selection native fallback
  degradeThreshold: number;      // count above which Tier A -> Tier B
}

Config helpers

function mergeOptions(base: HighlightOptions, override: HighlightOptions): HighlightOptions
function resolveOptions(input?: HighlightOptions): ResolvedOptions
const DEFAULT_OPTIONS: ResolvedOptions   // Deep-frozen resolved baseline.
  • mergeOptions deep-merges two partials: scalars take override; the namespaced groups (tip, ink, speed, edge, paper, glow, animation) merge field-wise; shape/markType collapse onto markType. Pure.
  • resolveOptions resolves a partial into a fully-defaulted ResolvedOptions. Pure and SSR-safe. Clamps opacity to 0-1, clamps speed fields, requires animation.duration positive, and falls non-finite numbers back to defaults. A palette with no color resolves to that family's default swatch.

ResolvedOptions is the same shape with every field non-optional and each group widened to its Resolved* form (ResolvedTip, ResolvedInk, ResolvedSpeedDynamics, ResolvedEdge, ResolvedPaper, ResolvedGlow, ResolvedAnimation), with gradient: GradientConfig | null, contrastBackground: ColorValue | null, and seed: number | null.


Geometry, RNG, and targeting exports

Advanced and SSR-oriented exports. Both @highlighters/core and @highlighters/core/path export the geometry, config, and RNG builders. Only the full core entry exports the targeting and tier-detection functions, since they touch the DOM.

Geometry builders (both entries):

buildMarkGeometry, buildClipPath, buildEdge, buildNoiseTile, buildNoiseTileDataUrl, buildPoolGradient

RNG (both entries): hashJitter, hashU32, mulberry

Targeting and observers (core only):

toRanges, rangesToLineRects, computeAnchor, collectPageRanges, findTextRanges,
createReflowObserver, createMutationWatcher, snapRangeToBounds

snapRangeToBounds is exported from core only, not from /path.

Pure geometry/data types (both entries): Box, LineRect, Anchor, EdgeVertex, PoolGradient, NoiseTile, MaskOffset, MarkGeometry, plus all enum/config/resolved types above. The /path entry omits all DOM-touching types (Target, TextTarget, PageTarget, MarkHandle, GroupHandle, Renderer, RenderContext, RenderEnvironment, ReflowCallback, MutationCallback, Disconnect, LineSpeedProfile) and the SpeedDynamicsOptions/ResolvedSpeedDynamics types.

Callback and teardown aliases (core only):

type ReflowCallback = () => void;
type MutationCallback = (records: MutationRecord[]) => void;
type Disconnect = () => void;

Framework bindings

All three bindings re-export the same convenience subset of core types: HighlightOptions, MarkHandle, GroupHandle, Target, TextTarget, PageTarget, PaletteName, PaletteSwatch, Palette, MarkType, ShapeType, TipType, EdgeCap, BlendMode, SnapMode, RendererTier, RendererTierPreference, GradientConfig, GradientStop, TipOptions, InkOptions, EdgeOptions, PaperOptions, GlowOptions, AnimationOptions.

React (@highlighters/react)

type HighlightTarget = React.RefObject<Element | null> | Target | null;

function useHighlight(
  target: HighlightTarget,
  options?: HighlightOptions,
  host?: HTMLElement | null,
): React.RefObject<MarkHandle | null>
import { useRef } from "react";
import { useHighlight, Highlight } from "@highlighters/react";

function Note() {
  const ref = useRef<HTMLParagraphElement>(null);
  useHighlight(ref, { palette: "mild" });
  return <p ref={ref}>Highlight me.</p>;
}

// Or the component (polymorphic, default <span>):
<Highlight as="p" options={{ markType: "underline", color: { palette: "mild", swatch: "pink" } }}>
  Highlight me.
</Highlight>;
  • useHighlight applies a mark to a ref, DOM node, or core Target and returns a ref to the live MarkHandle. It (re)creates the mark when the resolved target or host changes, re-checks each render so a RefObject populating after mount is picked up, pushes option changes via handle.update() without re-seeding (debounced by a JSON.stringify(options) key), and uses useLayoutEffect on the client / useEffect during SSR.
  • Highlight<E extends ElementType = "span"> renders an element whose text content is highlighted. Props: as?: E (default "span"), options?: HighlightOptions, host?: HTMLElement | null, plus any HTML attributes of E (passed through). Exported as HighlightProps<E> and HighlightOwnProps. Uses a callback ref so the hook tracks the node across as-swaps.

Vue (@highlighters/vue)

type HighlightTarget = Ref<Element | null> | Target;

function useHighlight(
  target: HighlightTarget,
  options?: MaybeRef<HighlightOptions | undefined>,
): () => MarkHandle | null
<script setup lang="ts">
import { ref } from "vue";
import { useHighlight, Highlight } from "@highlighters/vue";

const el = ref<HTMLElement | null>(null);
useHighlight(el, { palette: "mild" });
</script>

<template>
  <p ref="el">Highlight me.</p>
  <Highlight as="p" :options="{ markType: 'underline' }">Highlight me.</Highlight>
</template>
  • useHighlight applies a mark to a template ref (or core Target) and returns a getter for the live MarkHandle. It recreates when the bound element changes (watch), pushes option changes via handle.update() (deep watch, only registered when options is provided), sets up on onMounted, cleans up on onBeforeUnmount, and recreates the mark on the next sync if the target appears after setup.
  • Highlight is a DefineComponent with props as (keyof HTMLElementTagNameMap, default "span") and options (HighlightOptions, default undefined). inheritAttrs: false (non-prop attrs are spread onto the rendered element explicitly). Renders the default slot. Exposes { el, handle }, where handle is the useHighlight getter () => MarkHandle | null.

Svelte (@highlighters/svelte)

interface HighlightAction {
  update: (options?: HighlightOptions) => void;
  destroy: () => void;
}

function highlight(node: Element, options?: HighlightOptions): HighlightAction
<script lang="ts">
  import { highlight } from "@highlighters/svelte";
</script>

<p use:highlight={{ markType: "underline", palette: "mild" }}>Highlight me.</p>
  • update(next?) pushes new options through the live handle (preserves geometry; undefined becomes {}).
  • destroy() calls handle.remove().

Declarative usage

highlightAll() automatically marks every element carrying the data-highlight attribute within document.body, in addition to its page scan, and keeps them in sync via a mutation observer. There are no documented values for the attribute beyond its presence (it is selected via [data-highlight]). Subtrees marked data-highlight-exclude, or matching an exclude selector, are skipped. See Page-Highlighting.


See also: Getting-Started, Options-Reference, Recipes, Accessibility-and-Reflow, Limitations, FAQ.

Clone this wiki locally