Text Highlighter
Marker-pen sweep that draws in when the phrase scrolls into view.
0.8 KB gzippedDeps: motion/reactReduced-motion safeBase UI & Radix compatible
Every component ships its own receipts.
Installation
npx shadcn@latest add https://innsite.com.mx/r/text-highlighter.jsonInstalls with: motion
Source
"use client";
import { useRef } from "react";
import { motion, useInView, useReducedMotion } from "motion/react";
import { cn } from "@/lib/utils";
interface TextHighlighterProps {
children: React.ReactNode;
/** Any CSS colour; defaults to a translucent brand wash */
color?: string;
/** Seconds for the sweep */
duration?: number;
className?: string;
}
/**
* Marker-pen sweep that draws behind the text when it scrolls into view.
* Useful for the one phrase in a paragraph that has to land.
*/
export function TextHighlighter({
children,
color = "color-mix(in oklch, var(--brand) 30%, transparent)",
duration = 0.7,
className,
}: TextHighlighterProps) {
const ref = useRef<HTMLSpanElement>(null);
const inView = useInView(ref, { once: true, amount: 0.6 });
const reducedMotion = useReducedMotion();
return (
<span
ref={ref}
data-slot="text-highlighter"
className={cn("relative inline-block", className)}
>
{/* Painted first so the text stacks above it without a negative
z-index, which would fall behind an ancestor's background. */}
<motion.span
aria-hidden
initial={{ scaleX: 0 }}
animate={inView ? { scaleX: 1 } : { scaleX: 0 }}
transition={{
duration: reducedMotion ? 0 : duration,
ease: [0.22, 1, 0.36, 1],
}}
style={{ background: color }}
className="absolute -inset-x-1 inset-y-0 origin-left rounded-sm"
/>
<span className="relative">{children}</span>
</span>
);
}

