Magic UI
examplehighlighter-demosource: ok · hit
Highlighter Demo
Example showing the demo of a Highlighter
npx shadcn add "https://magicui.design/r/highlighter-demo"free-pro
"free-pro" library — installing requires an active license from the vendor.
No selection tags yet — empty means no evidence, not lack of support.
Dependencies
Bundle weight · mediumanimationmotion
Registry dependencies
@magicui/highlighter
Files2 · source cached 10/15/2026, 11:07:04 AM
registry/example/highlighter-demo.tsx
import { Highlighter } from "@/registry/magicui/highlighter"
export default function HighlighterDemo() {
return (
<div className="text-center">
<p className="leading-relaxed">
The{" "}
<Highlighter action="underline" color="#FF9800">
Magic UI Highlighter
</Highlighter>{" "}
makes important{" "}
<Highlighter action="highlight" color="#87CEFA">
text stand out
</Highlighter>{" "}
effortlessly.
</p>
</div>
)
}
registry/magicui/highlighter.tsx
"use client"
import { useLayoutEffect, useRef } from "react"
import type React from "react"
import { useInView } from "motion/react"
import { annotate } from "rough-notation"
import { type RoughAnnotation } from "rough-notation/lib/model"
type AnnotationAction =
| "highlight"
| "underline"
| "box"
| "circle"
| "strike-through"
| "crossed-off"
| "bracket"
interface HighlighterProps {
children: React.ReactNode
action?: AnnotationAction
color?: string
strokeWidth?: number
animationDuration?: number
iterations?: number
padding?: number
multiline?: boolean
isView?: boolean
}
export function Highlighter({
children,
action = "highlight",
color = "#ffd1dc",
strokeWidth = 1.5,
animationDuration = 600,
iterations = 2,
padding = 2,
multiline = true,
isView = false,
}: HighlighterProps) {
const elementRef = useRef<HTMLSpanElement>(null)
const isInView = useInView(elementRef, {
once: true,
margin: "-10%",
})
// If isView is false, always show. If isView is true, wait for inView
const shouldShow = !isView || isInView
useLayoutEffect(() => {
const element = elementRef.current
let annotation: RoughAnnotation | null = null
let resizeObserver: ResizeObserver | null = null
if (shouldShow && element) {
const annotationConfig = {
type: action,
color,
strokeWidth,
animationDuration,
iterations,
padding,
multiline,
}
const currentAnnotation = annotate(element, annotationConfig)
annotation = currentAnnotation
currentAnnotation.show()
resizeObserver = new ResizeObserver(() => {
currentAnnotation.hide()
currentAnnotation.show()
})
resizeObserver.observe(element)
resizeObserver.observe(document.body)
}
return () => {
annotation?.remove()
if (resizeObserver) {
resizeObserver.disconnect()
}
}
}, [
shouldShow,
action,
color,
strokeWidth,
animationDuration,
iterations,
padding,
multiline,
])
return (
<span ref={elementRef} className="relative inline-block bg-transparent">
{children}
</span>
)
}