Marker highlight
Also called highlighter, hand-drawn highlight, or rough notation
A hand-drawn highlighter stroke, underline, or circle that draws itself behind or around key words when they scroll into view.
import { useEffect, useRef, useState, type ReactNode } from 'react';
import { motion, useReducedMotion } from 'motion/react';
// Shapes drawn in a 100×40 box, scaled to each phrase's real size.
const MARKS = {
highlight: { d: 'M1 23 C 22 21.5, 52 24, 99 21.5', width: '0.95em', color: '#fde047' },
underline: { d: 'M2 34 C 30 28, 64 28, 98 31', width: '0.09em', color: '#2563eb' },
circle: {
d: 'M84 4 C 58 -2, 14 1, 4 15 C -4 28, 30 38, 58 37 C 88 36, 102 22, 92 10 C 88 5, 78 2, 66 3',
width: '0.075em',
color: '#db2777'
}
};
// Scales every x,y pair. Scaling the path, instead of stretching the SVG,
// keeps the stroke even and pathLength accurate.
function scalePath(d: string, sx: number, sy: number) {
let i = 0;
return d.replace(/-?\d*\.?\d+/g, (n) => String(Number(n) * (i++ % 2 ? sy : sx)));
}
type MarkerProps = { kind: keyof typeof MARKS; delay?: number; children: ReactNode };
// Use inside an `isolate` paragraph, so the highlight sits behind the words.
export function Marker({ kind, delay = 0, children }: MarkerProps) {
const reduceMotion = useReducedMotion();
const box = useRef<HTMLSpanElement>(null);
const [size, setSize] = useState({ w: 0, h: 0 });
const { d, width, color } = MARKS[kind];
useEffect(() => {
const el = box.current!;
const observer = new ResizeObserver(() =>
setSize({ w: el.offsetWidth, h: el.offsetHeight })
);
observer.observe(el);
return () => observer.disconnect();
}, []);
return (
// nowrap: the mark cannot follow the words onto a second line.
<span className='relative whitespace-nowrap'>
{children}
<span
ref={box}
aria-hidden
className={`pointer-events-none absolute -inset-x-[0.3em] -inset-y-[0.2em] ${kind === 'highlight' ? '-z-10' : ''}`}
>
{size.w > 0 && (
<svg viewBox={`0 0 ${size.w} ${size.h}`} className='block size-full overflow-visible'>
<motion.path
d={scalePath(d, size.w / 100, size.h / 40)}
fill='none'
stroke={color}
strokeWidth={width}
strokeLinecap='round'
initial={reduceMotion ? false : { pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay, ease: [0.65, 0, 0.35, 1] }}
/>
</svg>
)}
</span>
</span>
);
}Annotate the onboarding paragraph with marker highlights when it scrolls into view: a 0.95em-thick amber highlighter stroke behind "one thing at a time", a two-pass blue scribble under "skip ahead", and a loose pink circle around "under a minute". Draw each SVG path from pathLength 0 to 1 over 600ms with an ease-in-out curve, one after another. Measure each phrase with a ResizeObserver and scale the path to its size so the stroke stays even, keep the highlight behind the text, and show the marks fully drawn when prefers-reduced-motion is set.
Paste into Layerwise or any AI coding tool.
What is Marker highlight?
A marker highlight annotates a few words in running text the way you would with a pen. Each mark is an SVG path with a slightly wobbly shape: a thick stroke behind the words for a highlighter, a loose line under them for an underline, or an uneven loop around them for a circle. Animating the path from pathLength 0 to 1 makes it look drawn by hand, usually when the paragraph scrolls into view.
Use it to point at the phrases a reader should not miss: a key benefit on a landing page, a number in a case study, or a step in a tutorial. More than two or three marks per screen turns emphasis into noise.
Measure each phrase and scale the path to its real size. Stretching a fixed SVG with preserveAspectRatio="none" warps the stroke, and the usual fix, vector-effect: non-scaling-stroke, throws off the dash math that pathLength relies on. Put highlighter strokes behind the text inside an isolate parent, so the words stay crisp in light and dark themes. A mark cannot follow a line break, so keep marked phrases on one line with white-space: nowrap, and show the marks already drawn when someone prefers reduced motion.
Often confused with
- Underline animation
- An underline animation is a clean bar that grows under a link on hover. A marker highlight is a hand-drawn mark that draws itself to emphasize words in running text.
Related terms
All termsSVG line drawing
An animation that makes an SVG outline look like it is being drawn by hand, by revealing its stroke from start to end.
Underline animation
A link underline that draws itself on hover, growing from the left, from the center, or sweeping through, instead of simply appearing.
Scroll reveal
An animation that fades or slides content into place as it scrolls into view, so each section appears just as the reader reaches it.
Typographic hierarchy
Using differences in text size, weight, and color so people can tell at a glance what to read first, second, and last.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.