# Moving Text Can Be Paused

**MUST** · **ID:** `content-moving-text-can-be-paused` · **Category:** content
**Source:** [WCAG](https://www.w3.org/WAI/WCAG21/quickref/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/content-moving-text-can-be-paused

> MUST: Auto-scrolling tickers/marquees that run more than 5s alongside other content need a pause/stop/hide control (WCAG 2.2.2) and must stop under prefers-reduced-motion. Toggle animation-play-state and expose aria-pressed on the button.

Auto-scrolling tickers, marquees, and looping text need a pause control and must honor reduced-motion

A marquee or news ticker that scrolls on its own is a moving target the reader cannot catch — worse for anyone with a vestibular disorder, low vision, or a reading disability, for whom the movement is not decoration but an obstacle. WCAG 2.2.2 makes it concrete: anything that moves automatically for more than five seconds alongside other content must offer a pause, stop, or hide control. Two things satisfy it together: a visible Pause button (toggle animation-play-state, and expose aria-pressed), and a prefers-reduced-motion: reduce rule that stops the animation entirely for users who asked the OS to. Auto-motion is a convenience you offer, never one you impose.

## Rule snippet

```tsx
@media (prefers-reduced-motion: reduce){ .ticker{ animation: none } }
<button aria-pressed={paused} onClick={toggle}>Pause</button>
```

## Bad — do not do this

`content-moving-text-can-be-paused-bad`

```tsx
export function MovingTextCanBePausedBad() {
  const items = '⚡ 40% off ends tonight · Free shipping over $50 · New arrivals just dropped · ';
  return (
    <div className="w-full max-w-sm py-6">
      <style>{`@keyframes uig-ticker-bad{from{transform:translateX(0)}to{transform:translateX(-50%)}}`}</style>
      <div className="overflow-hidden rounded-md border border-border bg-card py-2">
        {/* Auto-scrolls forever, no control, no reduced-motion escape. */}
        <div
          className="whitespace-nowrap text-sm text-foreground"
          style={{ animation: 'uig-ticker-bad 8s linear infinite' }}
        >
          {items}
          {items}
        </div>
      </div>
      <p className="mt-4 text-xs text-destructive">
        The ticker never stops and has no pause — it fails WCAG 2.2.2, and reduced-motion users get no relief.
      </p>
    </div>
  );
}
```

## Good — do this

`content-moving-text-can-be-paused-good`

```tsx
import { useState } from 'react';

export function MovingTextCanBePausedGood() {
  const [paused, setPaused] = useState(false);
  const items = '⚡ 40% off ends tonight · Free shipping over $50 · New arrivals just dropped · ';
  return (
    <div className="w-full max-w-sm py-6">
      <style>{`@keyframes uig-ticker-good{from{transform:translateX(0)}to{transform:translateX(-50%)}}
        @media (prefers-reduced-motion: reduce){.uig-ticker-good{animation:none !important}}`}</style>
      <div className="flex items-center gap-2 rounded-md border border-border bg-card py-2 pl-2">
        <button
          onClick={() => setPaused((p) => !p)}
          aria-pressed={paused}
          className="shrink-0 rounded bg-muted px-2 py-0.5 text-xs text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
        >
          {paused ? 'Play' : 'Pause'}
        </button>
        <div className="overflow-hidden">
          <div
            className="uig-ticker-good whitespace-nowrap text-sm text-foreground"
            style={{ animation: 'uig-ticker-good 8s linear infinite', animationPlayState: paused ? 'paused' : 'running' }}
          >
            {items}
            {items}
          </div>
        </div>
      </div>
      <p className="mt-4 text-xs text-success">
        A pause control (WCAG 2.2.2) plus a reduced-motion stop: the motion is available, never forced.
      </p>
    </div>
  );
}
```

## References

- [WCAG 2.2.2 — Pause, Stop, Hide](https://www.w3.org/WAI/WCAG21/Understanding/pause-stop-hide.html)
- [MDN — prefers-reduced-motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion)
