Glitch Text
Print-misregistration glitch: two offset copies of the text in accent and secondary colors jitter in horizontal slices, constantly or only on hover/focus. Pure CSS, blend mode adapts to dark.
brutalist/effect/glitch-textSource
import { cn } from "@/lib/utils";
export interface GlitchTextProps {
/** Text to render (also duplicated in the glitch layers). */
children?: string;
/** Glitch constantly, or only on hover/focus of the element or a parent `group`. */
trigger?: "always" | "hover";
as?: "h1" | "h2" | "h3" | "p" | "span";
className?: string;
}
/**
* Print-misregistration glitch: two offset copies in primary and accent colors
* jitter in horizontal slices. Pure CSS.
*/
export function GlitchText({ children = "Breaking change", trigger = "always", as: Tag = "h2", className }: GlitchTextProps) {
return (
<Tag className={cn("brutalist-glitch relative inline-block font-da-display tracking-da-display", trigger === "hover" && "is-hover", className)}>
{children}
<span aria-hidden className="brutalist-glitch-a absolute inset-0 text-da-accent">
{children}
</span>
<span aria-hidden className="brutalist-glitch-b absolute inset-0 text-da-secondary">
{children}
</span>
<style href="brutalist-glitch" precedence="default">{`
.brutalist-glitch > span { opacity: 0; pointer-events: none }
.brutalist-glitch:not(.is-hover) > span,
.brutalist-glitch.is-hover:hover > span,
.group:hover .brutalist-glitch.is-hover > span,
.group:focus-visible .brutalist-glitch.is-hover > span { opacity: 1 }
.brutalist-glitch-a { animation: brutalist-glitch-a 2.4s steps(1) infinite; mix-blend-mode: multiply }
.brutalist-glitch-b { animation: brutalist-glitch-b 2.4s steps(1) infinite; mix-blend-mode: multiply }
:where(.dark) .brutalist-glitch > span, .dark.brutalist-glitch > span { mix-blend-mode: screen }
@keyframes brutalist-glitch-a {
0%, 100% { clip-path: inset(0 0 100% 0); translate: 0 }
8% { clip-path: inset(10% 0 60% 0); translate: -4px 0 }
16% { clip-path: inset(55% 0 20% 0); translate: 5px 0 }
24% { clip-path: inset(0 0 100% 0) }
60% { clip-path: inset(70% 0 5% 0); translate: -3px 0 }
66% { clip-path: inset(0 0 100% 0) }
}
@keyframes brutalist-glitch-b {
0%, 100% { clip-path: inset(100% 0 0 0); translate: 0 }
10% { clip-path: inset(40% 0 35% 0); translate: 4px 0 }
18% { clip-path: inset(80% 0 2% 0); translate: -5px 0 }
26% { clip-path: inset(100% 0 0 0) }
62% { clip-path: inset(20% 0 60% 0); translate: 3px 0 }
68% { clip-path: inset(100% 0 0 0) }
}
@media (prefers-reduced-motion: reduce) { .brutalist-glitch > span { animation: none; opacity: 0 !important } }
`}</style>
</Tag>
);
}
export default GlitchText;
modules/brutalist/effect/glitch-text/index.tsx
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | string | "Breaking change" | Text (string only, duplicated in layers). |
| trigger | "always" | "hover" | "always" | Always on, or on hover of itself / a parent .group (focus-visible too). |
| as | "h1" | "h2" | "h3" | "p" | "span" | "h2" | Element. |
| className | string | — | Classes on the element. |
Other text variants in Brutalist
Marquee Band
Tilted full-bleed ticker band with giant uppercase words scrolling infinitely between ruled strokes. Seamless loop, direction and speed props, three color tones.
Scramble Text
Decoder-style mono text: random glyphs resolve left to right into the final string when it scrolls into view, and again on hover or focus. Great for version numbers, stats and labels.
Typewriter Text
Headline with a static prefix and a rotating last word that is typed character by character, held, deleted and replaced, followed by a blinking block cursor.
Text in other art directions
Count Up
Number that counts up with an expo-out ease and tabular digits when scrolled into view; prefix, suffix, decimals and locale-aware thousands separators.
Gradient Text
Inline text filled with a slowly flowing gradient built from the primary and accent tokens (bg-clip-text); animated or static. Pure CSS.
Rotating Words
Headline with a static prefix and a highlighted word that slides up to the next one on an interval, inside a slot whose width animates to fit each word.
Text Shimmer
Loading/live text effect: a light band sweeps across muted text using a clipped gradient. For "thinking…", "generating…" or live status labels. Pure CSS, server-safe.
Digit Roll
Odometer-style number: each digit rolls vertically through 0–9 to its value (staggered from the left) when it enters the viewport, in tabular display figures.
Outline Fill
Outlined display text (hairline stroke, transparent fill) that fills solid ink from bottom to top on hover/focus via a clipped duplicate layer — for big navigation links. Pure CSS.
Scramble Text
Mono text that resolves from random glyphs to the real string left-to-right when it enters the viewport (and again on hover); final text is always exposed to assistive tech.
Tracking In
Headline whose letter-spacing contracts from very wide to the tight display tracking while fading in — a calm, precise entrance for short words.
Count Up
Number that counts up with an ease-out when scrolled into view, formatted with thousands separators (prefix/suffix, decimals); tabular figures prevent jitter. Final value for screen readers.
Shimmer Text
Text filled with a primary→accent-fg gradient and a slow light sweep passing across it every few seconds — for a single highlighted phrase in a headline. Pure CSS.
Typed Words
Headline with a rotating keyword typed and erased character by character in primary, with a blinking caret; reduced motion swaps whole words. Full sentence exposed to screen readers.
Word Reveal
Headline whose words slide up from behind a mask one after another when scrolled into view — crisp, no blur or bounce. The element keeps its plain text for screen readers.
Drawn Underline
Hand-drawn underline that draws itself (SVG pathLength) beneath a word when it scrolls into view — a loose, slightly wavy pen stroke.
Italic Swap
Headline with a rotating italic serif word: each word slides up out of a mask and the next rises in with a soft ease; the full sentence is available to screen readers.
Letter Rise
Letters drift up from below with a gentle fade, one after another like seeds sprouting, when the text scrolls into view; words never break mid-letter.
Marker Highlight
Highlighter-pen effect: a soft tinted band sweeps left-to-right behind the words when they scroll into view; works across line wraps (box-decoration-break) and text stays fully legible.
Emoji Swap
Headline whose last word is a pastel pill (emoji + word) that pops out and swaps to the next one on an interval — teams, freelancers, students…
Highlight Text
Marker highlight that draws itself behind a word or phrase — left to right, slightly tilted and rounded — when it scrolls into view; four pastel tones.
Rolling Number
Odometer-style number: each digit rolls vertically to its value with a staggered bounce, on first view and whenever the value changes.
Wave Text
Bouncy text where letters hop one after another in a wave — always, or on hover/focus of the text or a parent .group. Pure CSS.