Hand-drawn text annotations that draw themselves in like ink as they scroll into view, with an optional animate prop for a fully static render.
npx shadcn@latest add @iconiq/markerimport { Marker } from "@/components/ui/marker";
export function MarkerPreview() {
return (
<p>
The quick brown fox jumps over the <Marker>lazy dog</Marker>.
</p>
);
}childrenText or inline content to annotate.
Type ReactNode
variantHand-drawn annotation style.
Type "wavy" | "circle" | "highlight" | "underline" | "line" | "dottedUnderline" | "doubleUnderline" | "strikethrough" | "crossOut" | "arrow" | "bracket" | "box"·Default "wavy"
colorOverrides the variant's default ink color. Accepts a Tailwind text-color class, such as text-pink-400.
Type string
animateWhether the decoration draws itself in when scrolled into view. Set to false to render it fully static.
Type boolean·Default true
durationDraw duration in seconds for a single stroke.
Type number·Default 0.7
delayDelay in seconds before the draw-in starts.
Type number·Default 0
classNameOptional class names applied to the wrapping span.
Type string
The draw-in plays once per instance, the first time it scrolls into view, and always respects prefers-reduced-motion.
Animation is driven by whileInView with viewport once: true, so each Marker draws itself in a single time and stays drawn on subsequent scrolls.
When useReducedMotion() reports a reduced-motion preference, or when animate is false, every stroke renders fully drawn immediately with no motion.
Stroke variants animate through Motion's pathLength, which works for any curve without measuring the path in JavaScript.
The highlight fill can't use pathLength since it has no stroke to trace, so it sweeps in with a left-anchored scaleX instead.
Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.
Dependencies: motion.
Contact
Additionally, if you find any bug or issue, feel free to raise an issue.