Source Code

<div class="scene">
  <h1 class="glitch" data-text="GLITCH">GLITCH</h1>
  <p class="sub">CSS-only glitch effect using pseudo-elements and clip-path animation</p>
  <div class="btns">
    <button class="btn" onclick="setWord('GLITCH')">GLITCH</button>
    <button class="btn" onclick="setWord('ERROR')">ERROR</button>
    <button class="btn" onclick="setWord('SYSTEM')">SYSTEM</button>
    <button class="btn" onclick="setWord('BREACH')">BREACH</button>
  </div>
</div>

Glitch Text — Free HTML CSS Cyberpunk Snippet

Glitch Text Effect · Animations · Plain HTML, CSS & JS · Live preview

What's included

Features

.glitch: :before/.after pseudo-elements display content: attr(data-text) — same text as element
Three layers: main element + two pseudo-elements, all absolutely positioned
clip-path: rect() slices each pseudo-element into different horizontal strips per keyframe
translateX and scaleX offsets on each layer mimic RGB channel separation
glitch-main animation on the base element adds coordinated shake
setWord(w) updates both textContent and dataset.text simultaneously
Monospace font + cyan colour + text-shadow for terminal/digital aesthetic
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons
Live split-pane editor — preview updates as you type

About this UI Snippet

Glitch Text — ::before/::after Layered Copies, clip-path Slices & Channel Offset

Screenshot of the Glitch Text Effect snippet rendered live

The glitch text effect simulates digital signal corruption — the text appears to tear apart into colour-separated layers that momentarily misalign. Used on cyberpunk interfaces (pair it with matrix rain and neon glow buttons), gaming titles, error screens, and dark-themed products communicating disruption.

The effect uses three layers: the original .glitch element, .glitch::before, and .glitch::after. Both pseudo-elements display the same text via content: attr(data-text) — the same value set on the element in the HTML. All three layers are absolutely positioned on top of each other.

CSS @keyframes glitch-1 and glitch-2 apply different clip-path: rect() values to each pseudo-element at different frames, slicing each into horizontal strips. translateX() and scaleX() offsets separate the cyan (::before) and red (::after) colour channels, mimicking RGB misalignment in a corrupted video signal.

The setWord(w) JS function updates both element textContent and dataset.text simultaneously to keep the pseudo-element content in sync.

The CSS animation mechanics

Two ::before and ::after pseudo-elements are stacked on top of the base text using position: absolute; inset: 0. Each has content: attr(data-text) to display the same text. They use clip-path: rect(Npx, 9999px, Mpx, 0) to show only a horizontal slice of the text at a time — this creates the "torn apart lines" look. CSS keyframes shift the slices at different random offsets: transform: translate(-2px, 3px) and transform: translate(3px, -2px). The red and cyan colour shift uses text-shadow and mix-blend-mode: screen to simulate RGB channel separation.

The animation timing

The glitch animation runs in short bursts: steps() timing with very fast keyframes (0.08s total) creates a jerky, digital corruption feel rather than a smooth animation. Using animation-iteration-count: infinite with random-length pauses (via multiple steps in the keyframe) simulates the irregular nature of actual digital glitches.

Adding glitch to any element

The snippet uses data-text attribute to clone content into pseudo-elements — this is the only technique that works for CSS-only text duplication. Add data-text="Your text" to any element and apply the glitch CSS class. Dynamic text changes need the data-text attribute updated via JavaScript: el.dataset.text = el.textContent.

Triggering glitch on hover vs continuous

The snippet animates continuously by default. For a hover-only glitch, add animation-play-state: paused to the base state and animation-play-state: running on :hover. This triggers the glitch only when the user mouses over the text — a common pattern for interactive headings on portfolio sites.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than eyeballing the keyframe percentages, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the glitch-1 and glitch-2 keyframes fire only in narrow late-percentage windows (86 to 92 percent, for instance) instead of running continuously, and how content: attr(data-text) on the ::before and ::after layers lets a single data attribute drive both color-split copies of the same word. It can also help you optimize it, for example checking whether animating clip-path and transform on three stacked layers is cheap enough to run on many headings at once, or whether it should be paused off-screen. For extending it, ask it to add a hover-only trigger using animation-play-state, wire setWord to cycle automatically through a phrase list, or layer in a text-scramble decode before the glitch settles. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a CSS-only RGB-split glitch text effect in plain HTML and CSS, driven by a small JavaScript helper for swapping the displayed word, using only pseudo-elements and clip-path — no canvas, no images, no external libraries.

Requirements:
- A single heading element carrying its visible text as both its text content and a data-text HTML attribute, since pseudo-elements cannot read a parent's textContent directly.
- Two pseudo-elements, ::before and ::after, both set to content: attr(data-text) and absolutely positioned exactly over the base element, one tinted a distinct accent color (for example cyan) and the other a contrasting color (for example red or green), each with its own colored text-shadow glow.
- CSS keyframe animations on each pseudo-element that use clip-path polygon values to reveal only a thin horizontal strip of that copy's text at specific late-percentage keyframe steps, combined with small translateX offsets, so most of the animation loop shows no distortion and the glitch reads as a brief, irregular flicker rather than a constant effect.
- A separate, subtler keyframe on the base element itself (small skewX oscillations at similarly narrow percentage windows) so the whole word shudders slightly in sync with the color-split layers.
- A JavaScript function that accepts a new word, updates both the element's textContent and its data-text attribute together (they must never go out of sync), and wire it to at least three buttons offering different words.
- The animation must run on an infinite loop by default, and note in a comment how to make it hover-triggered instead using animation-play-state.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Watch the glitch animateThe text glitches continuously via CSS keyframes. Click the phrase buttons to swap to a different word and watch the glitch animate the new text.
  2. 2
    Update the wordsIn the HTML panel, change the button labels and the onclick setWord() arguments to your own phrases.
  3. 3
    Change the glitch coloursUpdate color on .glitch::before (cyan) and .glitch::after (red) in the CSS panel to any colour pair.
  4. 4
    Adjust glitch intensityIn the CSS keyframes, increase the translateX values and clip-path rect offsets for more aggressive glitching.
  5. 5
    Pause the animation on hoverAdd .glitch:hover { animation-play-state: paused } to freeze the glitch on hover.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Cyberpunk and hacker aesthetic title screens
Glitch is the defining animation of cyberpunk, hacker, and sci-fi interfaces. Use on main title headings, loading screens, and error pages where the aesthetic communicates digital instability, corrupted data, or high-tech environments.
Error page and access denied headings
Apply to "404", "ERROR", or "ACCESS DENIED" headings on error pages. The glitch effect matches the failure theme semantically — corrupted text communicates a corrupted state, making the error feel intentional rather than accidental.
Learn CSS clip-path animation and channel separation
The effect layers three copies of the same text using content: attr(data-text). CSS keyframes slice each copy with clip-path: rect() and offset them with translateX to separate RGB colour channels. Edit each keyframe in the CSS panel to see how slicing and offsetting create the distortion.
Interactive word swap on button click
Wire the setWord() function to any trigger — a "Next" button cycles through phrases with a glitch transition between each one. The scramble effect provides a visual bridge between the old and new content.
Product name and brand reveals
Use for a dramatic product name reveal on a launch page. The text glitches for a moment before resolving into the actual name — creating a cinematic reveal that suggests the product has emerged from chaos.
Combine with text scramble for layered effects
Trigger the Text Scramble snippet first (characters decode to the word), then start the Glitch animation on the resolved text for a two-stage reveal: scramble → resolve → glitch → stable. The setWord() functions work together.
Related: Matter.js Confetti Cannon
See the Matter.js Confetti Cannon for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

.glitch::before and .glitch::after are absolutely positioned on top of the original element. Both use content: attr(data-text) which reads the data-text HTML attribute — the same value as the element's textContent. All three layers overlap perfectly until the keyframe animations offset them.

CSS pseudo-elements cannot read their parent's textContent directly. data-text is an HTML attribute that mirrors the text, and content: attr(data-text) reads it. setWord(w) updates both el.textContent and el.dataset.text simultaneously to keep them in sync.

clip-path: rect(top, right, bottom, left) clips the element to a rectangle. Different rect() values in the keyframes create the horizontal slice effect — each pseudo-element shows only a specific band of the text at any given keyframe, creating the torn-apart appearance.

Remove the animation property from .glitch, .glitch::before, and .glitch::after. Add .glitch:hover, .glitch:hover::before, .glitch:hover::after { animation: ... }. The glitch fires only when hovered and stops when the cursor leaves.

In the keyframe percentages, make most of the animation frames have no transform applied: 0%,2%,4%,100% { ... } with only 1% and 3% having the glitch transforms. This makes the glitch occur only briefly at those percentages — 98% of the time the text is stable.

Yes. Manage the displayed word in useState. Set both the element text and data-text via React: <h1 className="glitch" data-text={word}>{word}</h1>. The CSS animations work without any React changes. To cycle words, use a setInterval that updates the word state.