Text Highlighter
Text Highlighter is a React and Tailwind CSS text component from Magic UI, licensed MIT. Copy it and paste it into your project.
Magic UI
MIT
text
What it is
Text Highlighter is a React and Tailwind CSS text component from Magic UI, licensed MIT. Copy it and paste it into your project.
How to use it
Open it in the catalogue, press copy, and paste it into your project. The prompt you copy carries the code and the rules that tell your agent to reproduce it without changing anything.
Five free copies a month. No card.
Needs
npm i motion rough-notation
Licence
This component comes from Magic UI and is redistributed under the MIT licence, which permits commercial use. The copyright notice travels with the code.
Text Highlighter
"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>
)
}