-
-
Notifications
You must be signed in to change notification settings - Fork 3
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 nopresetoption and no named-color shorthand in the actual API.HighlightOptionshas nopresetfield, andcoloris 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.
| 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.
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
-
hostis an optional positioned element to mount the overlay inside (for transformed, scrolling, or stacked containers). It is promoted toposition: relativeif static. Defaults to the document body. - Default
snapis 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.
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
snapis"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().
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
snapis"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
speedgroup) engages here only, and only during a primary-button fine-pointer drag. It is suppressed underprefers-reduced-motionand is a no-op for programmatic/keyboard/static selections or whenspeed.enabledisfalse. See Ink-and-Optics. -
update(opts)composes additively across calls (options accumulate viamergeOptions). -
remove()detaches theselectionchange, pointer, and tracker listeners. - The
tiergetter returns the live renderer's tier, or"css"before first mount.
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
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.
}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.
}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. |
interface TextTarget {
text: string | RegExp; // Every match within root, including matches spanning inline boundaries.
root?: Element | Document; // Defaults to document.body.
}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.
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(...)).
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.
}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.
}| 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.
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.
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) |
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.
): RendererTierWith 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
}function mergeOptions(base: HighlightOptions, override: HighlightOptions): HighlightOptions
function resolveOptions(input?: HighlightOptions): ResolvedOptions
const DEFAULT_OPTIONS: ResolvedOptions // Deep-frozen resolved baseline.-
mergeOptionsdeep-merges two partials: scalars takeoverride; the namespaced groups (tip,ink,speed,edge,paper,glow,animation) merge field-wise;shape/markTypecollapse ontomarkType. Pure. -
resolveOptionsresolves a partial into a fully-defaultedResolvedOptions. Pure and SSR-safe. Clampsopacityto 0-1, clampsspeedfields, requiresanimation.durationpositive, and falls non-finite numbers back to defaults. Apalettewith nocolorresolves 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.
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, buildPoolGradientRNG (both entries): hashJitter, hashU32, mulberry
Targeting and observers (core only):
toRanges, rangesToLineRects, computeAnchor, collectPageRanges, findTextRanges,
createReflowObserver, createMutationWatcher, snapRangeToBoundssnapRangeToBounds 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;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.
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>;-
useHighlightapplies a mark to a ref, DOM node, or coreTargetand returns a ref to the liveMarkHandle. It (re)creates the mark when the resolved target orhostchanges, re-checks each render so aRefObjectpopulating after mount is picked up, pushes option changes viahandle.update()without re-seeding (debounced by aJSON.stringify(options)key), and usesuseLayoutEffecton the client /useEffectduring 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 ofE(passed through). Exported asHighlightProps<E>andHighlightOwnProps. Uses a callback ref so the hook tracks the node acrossas-swaps.
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>-
useHighlightapplies a mark to a template ref (or coreTarget) and returns a getter for the liveMarkHandle. It recreates when the bound element changes (watch), pushes option changes viahandle.update()(deepwatch, only registered whenoptionsis provided), sets up ononMounted, cleans up ononBeforeUnmount, and recreates the mark on the next sync if the target appears after setup. -
Highlightis aDefineComponentwith propsas(keyof HTMLElementTagNameMap, default"span") andoptions(HighlightOptions, defaultundefined).inheritAttrs: false(non-prop attrs are spread onto the rendered element explicitly). Renders the default slot. Exposes{ el, handle }, wherehandleis theuseHighlightgetter() => MarkHandle | null.
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;undefinedbecomes{}). -
destroy()callshandle.remove().
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.
Getting Started
The Mark
- Mark-Types-and-Shapes
- Tips-and-Edges
- Ink-and-Optics
- Color-and-Palettes
- Snapping-and-Overshoot
- Animation
Targeting
Reference
Production