Karaoke Text
Lyric lines colored character by character along a timeline, with the current line scaled up in focus.
Multiple lyric lines play along a timeline: the current line scales up in focus, a gradient sweeps its characters from left to right, sung lines fade out and drift up, and the whole sheet scrolls automatically to keep the current line centered. Play, pause, and restart controls are built in, and playing can also be fully controlled — well suited to music product pages, lyric showcases, and rhythmic taglines.
npx shadcn@latest add https://webberui.com/r/karaoke-text.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<KaraokeText />
Installation
npx shadcn@latest add https://webberui.com/r/karaoke-text.jsonOr, once registries are configured in components.json, install it as @webberui/karaoke-text.
Usage
import { KaraokeText } from "@/components/ui/karaoke-text";
<KaraokeText
lines={[
{ text: "The first line of the lyrics", duration: 2400 },
{ text: "The second line of the lyrics", duration: 2600 },
{ text: "The third line of the lyrics" },
]}
height={220}
className="text-xl font-semibold"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
lines | KaraokeLine[] | — | Array of lyric lines, where KaraokeLine is { text: string; duration?: number } (milliseconds) |
playing | boolean | — | Controlled playback state; when omitted, the component manages it internally |
onPlayingChange | (playing: boolean) => void | — | callback for playback state changes (fired on control clicks and when playback ends) |
autoPlay | boolean | true | Whether playback starts automatically in uncontrolled mode |
loop | boolean | true | Whether to loop back to the start after the last line |
showControls | boolean | true | Whether to show the built-in play / pause / restart control bar |
height | number | 240 | Height of the lyric viewport (px); the current line auto-scrolls to the center |
defaultDuration | number | 2400 | Default duration for lines with no duration (milliseconds) |
activeScale | number | 1.12 | Scale factor of the current line |
baseClassName | string | greyscale text color | Class for the color of text not yet sung |
fillClassName | string | amber → rose → fuchsia gradient | Class for the gradient fill of sung text (colored via bg-clip-text) |
onLineChange | (index: number) => void | — | callback fired when the current line index changes |
className | string | — | forwarded to the outermost container; font size and weight are inherited by the lyric lines |
Accessibility
- When the user has "reduce motion" enabled at the system level, there is no per-character sweep, scaling, or blur — the current line is simply highlighted with the full fill, and lines still advance along the timeline
- The underlying lyrics are real text that the screen reader can announce; the gradient fill layer is a decorative copy marked
aria-hidden - The play, pause, and restart buttons all carry an
aria-label, and the current line number is shown (for example03 / 06) as a visual confirmation - rAF pauses automatically when the tab goes to the background, and resumes with a clamped time delta on return, so it never jumps lines
Blur Reveal Text
A whole passage comes into focus line by line from a heavy blur on entering the viewport — made for narrative paragraphs.
Overprint Register
A heading rendered as several overprinted colour plates that slide in from misalignment into exact register when they enter the viewport, then drift slightly out of register again on hover.