A GSAP glitch effect makes a headline look briefly disrupted: its position jumps, coloured edges separate, then everything settles back into readable text. The useful part is the return to normal. Keep the distortion short enough that the headline still does its job.

Here’s a basic implementation using one text element, CSS text shadows and GSAP core. The words stay in the HTML throughout, with no character replacement or extra copies for screen readers to navigate.

What you’ll build

A static headline with a button that plays a short glitch burst. Two coloured shadows move in opposite directions while the headline shifts a few pixels, then the effect resets. There is no automatic loop, and visitors who request reduced motion see the static headline.

The preview below is the full Vault product, which has several glitch styles. The tutorial builds a simpler colour-shadow version.

The full Glitch Text Effect, which this tutorial builds a simpler version of. Hover a headline or use the trigger button inside the frame. Get the full code →

Step 1: Add the headline and button

Put this markup inside the body of your page:

<section class="glitch-example" aria-labelledby="glitch-title">
  <h2 id="glitch-title" class="glitch-heading">Signal interrupted</h2>
  <button class="glitch-replay" type="button" disabled>Play glitch</button>
  <p class="glitch-motion-note">Animation is off while reduced motion is enabled.</p>
</section>

The button starts disabled. The script enables it only when GSAP is available and motion is allowed, so a failed script download does not leave a working-looking control with no action. A native button also gives you touch, Enter and Space activation without separate event handlers.

Step 2: Style the static state

Add this CSS to your stylesheet or a <style> element in the head:

.glitch-example {
  padding: clamp(1.5rem, 5vw, 4rem);
  background: #16161a;
  color: #f5f5f2;
}

.glitch-heading {
  --glitch-offset: 0px;
  margin: 0 0 1.5rem;
  font-family: system-ui, sans-serif;
  font-size: clamp(2rem, 7vw, 5rem);
  font-weight: 800;
  line-height: 1.1;
  overflow-wrap: anywhere;
  text-shadow:
    var(--glitch-offset) 0 0 #ff597e,
    calc(0px - var(--glitch-offset)) 0 0 #65e7ed;
}

.glitch-replay {
  padding: 0.75rem 1rem;
  border: 1px solid currentColor;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font: 600 1rem system-ui, sans-serif;
  cursor: pointer;
}

.glitch-replay:focus-visible {
  outline: 3px solid #65e7ed;
  outline-offset: 4px;
}

.glitch-replay:disabled {
  opacity: 0.6;
  cursor: default;
}

.glitch-motion-note {
  display: none;
  font: 1rem/1.5 system-ui, sans-serif;
}

@media (prefers-reduced-motion: reduce) {
  .glitch-motion-note { display: block; }
}

At zero offset, both shadows sit directly behind the text. Increasing --glitch-offset separates the pink and cyan edges. This is a colour-split approximation, not a simulation of independent RGB channels, but it needs only a single heading.

The padding leaves room for the small displacement. The responsive font size and wrapping keep a longer headline inside the section on a phone.

Step 3: Load GSAP

Place this script after the markup, before the closing </body> tag:

<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>

This example needs only the core library. If your page already loads GSAP, use that copy.

Step 4: Animate a short burst

Add the following code inside a <script> element immediately after the GSAP include:

const example = document.querySelector('.glitch-example');

if (example && window.gsap) {
  const heading = example.querySelector('.glitch-heading');
  const button = example.querySelector('.glitch-replay');
  const media = gsap.matchMedia();

  media.add('(prefers-reduced-motion: no-preference)', () => {
    const burst = gsap.timeline({
      paused: true,
      defaults: { ease: 'steps(1)' }
    });

    burst
      .to(heading, { x: -3, '--glitch-offset': '4px', duration: 0.12 })
      .to(heading, { x: 2, '--glitch-offset': '2px', duration: 0.18 })
      .to(heading, { x: -1, '--glitch-offset': '5px', duration: 0.14 })
      .to(heading, {
        x: 0,
        '--glitch-offset': '0px',
        duration: 0.22,
        ease: 'power2.out'
      });

    function playGlitch() {
      if (!burst.isActive()) burst.restart();
    }

    button.disabled = false;
    button.addEventListener('click', playGlitch);

    return () => {
      button.removeEventListener('click', playGlitch);
      button.disabled = true;
    };
  });
}

The GSAP timeline sequences the offsets. steps(1) makes each movement a jump; the final tween eases back to the resting state. Rapid clicks do not stack animations because the handler ignores activation while the burst is active.

GSAP matchMedia creates the timeline only when motion is allowed. If the preference changes, GSAP reverts the animations created inside the callback. The cleanup removes the click handler and disables the button. Switching motion back on creates a fresh timeline and reconnects the control.

For an application that removes this section without a page reload, retain the media object in your component and call media.revert() when it unmounts.

Making it yours

  • Change the shadow colours to suit the page. The main text should remain legible without relying on the coloured edges.
  • Keep displacement small. The x values move the entire headline, while --glitch-offset controls only the shadows.
  • Change the rhythm by adjusting the first three durations. Irregular spacing gives the burst a disrupted feel; the last tween makes the return deliberate.
  • Use a short phrase. A glitch on a heading can add character. Applying it to a paragraph interrupts reading.

Keep the background and main text brightness steady. This example shifts edges rather than alternating full-area light and dark frames. Reduced-motion support does not make every possible glitch design safe: avoid strobes, large flashing regions and aggressive automatic repetition.

If the effect doesn’t play

Check that the main script runs after the markup and GSAP include. If the button stays disabled, look for a failed GSAP request in the browser’s Network panel and check your system’s reduced-motion setting.

If the colours are barely visible, confirm that the custom property is being animated and that another CSS rule isn’t replacing text-shadow. A zero offset is intentionally the clean resting state.

Text shadows require painting as their offsets change. Keep this treatment to a short heading and test on the devices your audience uses before multiplying it across a page.

That’s it

Activate Play glitch and the headline briefly separates, shifts and settles. The text remains selectable, the control works from the keyboard, and reduced-motion visitors get the static version.

For a different kind of text animation, the six-approach GSAP text animation guide compares reveals, typewriters, scramble, glitch and other treatments.


Want more control?

The full Glitch Text Effect adds:

  • Four styles: displacement shift, RGB chromatic aberration, VHS scan slice and character chaos.
  • Hover, focus, click, scroll-into-view and interval triggers.
  • Randomised bursts, intensity presets and duration controls.
  • A shared trigger button for multiple glitch elements.

View the full effect with all options →

Browse the GSAP text effects category for finished text animations with live demos, or every GSAP example with a live demo on one page.