# Pause, Stop, Hide Controls (WCAG 2.2.2)

**MUST** · **ID:** `animations-pause-stop-hide` · **Category:** animations
**Source:** [WCAG](https://www.w3.org/WAI/WCAG21/quickref/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/animations-pause-stop-hide

> MUST: Auto-playing animations >5s MUST have pause/stop/hide controls; OR auto-stop after 5s. Applies to carousels, video backgrounds, infinite loops. Essential animations (loading spinners, progress) are exempt.

Auto-playing animations over 5 seconds must have pause/stop/hide controls

WCAG 2.2.2 Level A requires that users can pause, stop, or hide moving content. This prevents distraction for users with attention disorders and reduces seizure risk. Loading indicators and progress bars are exempt as they provide essential feedback.

## Bad — do not do this

`animations-pause-stop-hide-bad`

```tsx
export function PauseStopHideBad() {
  return (
    <div className="space-y-4">
      <div className="relative h-32 bg-muted rounded-lg overflow-hidden">
        {/* Auto-playing carousel with no pause controls */}
        <div
          className="absolute inset-0 flex items-center justify-center"
          style={{
            animation: 'slideCarousel 6s linear infinite',
          }}
        >
          <div className="flex gap-4">
            <div className="w-24 h-20 bg-primary rounded-md flex items-center justify-center text-primary-foreground text-xs">
              Slide 1
            </div>
            <div className="w-24 h-20 bg-primary rounded-md flex items-center justify-center text-primary-foreground text-xs">
              Slide 2
            </div>
            <div className="w-24 h-20 bg-primary rounded-md flex items-center justify-center text-primary-foreground text-xs">
              Slide 3
            </div>
          </div>
        </div>
      </div>
      <style>{`
        @keyframes slideCarousel {
          0%, 30% { transform: translateX(0); }
          33%, 63% { transform: translateX(-128px); }
          66%, 96% { transform: translateX(-256px); }
          100% { transform: translateX(0); }
        }
      `}</style>
      <p className="text-xs text-destructive">
        ✗ Carousel auto-plays forever with no pause/stop controls (WCAG 2.2.2 violation)
      </p>
    </div>
  );
}
```

## Good — do this

`animations-pause-stop-hide-good`

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

export function PauseStopHideGood() {
  const [isPaused, setIsPaused] = useState(false);
  const [currentSlide, setCurrentSlide] = useState(0);

  useEffect(() => {
    if (isPaused) return;

    const timer = setInterval(() => {
      setCurrentSlide((prev) => (prev + 1) % 3);
    }, 2000);

    return () => clearInterval(timer);
  }, [isPaused]);

  return (
    <div className="space-y-4">
      <div className="relative h-32 bg-muted rounded-lg overflow-hidden">
        {/* Carousel with pause control */}
        <div
          className="absolute inset-0 flex items-center justify-center transition-transform duration-500"
          style={{
            transform: `translateX(-${currentSlide * 128}px)`,
          }}
        >
          <div className="flex gap-4">
            <div className="w-24 h-20 bg-primary rounded-md flex items-center justify-center text-primary-foreground text-xs">
              Slide 1
            </div>
            <div className="w-24 h-20 bg-primary rounded-md flex items-center justify-center text-primary-foreground text-xs">
              Slide 2
            </div>
            <div className="w-24 h-20 bg-primary rounded-md flex items-center justify-center text-primary-foreground text-xs">
              Slide 3
            </div>
          </div>
        </div>

        {/* Pause/Play control */}
        <button
          onClick={() => setIsPaused(!isPaused)}
          className="absolute bottom-2 right-2 px-2 py-1 bg-background/90 rounded text-xs font-medium hover:bg-background focus:outline-hidden focus-visible:ring-2 focus-visible:ring-primary"
          aria-label={isPaused ? 'Play carousel' : 'Pause carousel'}
        >
          {isPaused ? '▶ Play' : '⏸ Pause'}
        </button>
      </div>
      <p className="text-xs text-success">
        ✓ Carousel has pause/play control - meets WCAG 2.2.2 Pause, Stop, Hide
      </p>
    </div>
  );
}
```

## References

- [WCAG 2.2.2 Understanding](https://www.w3.org/WAI/WCAG21/Understanding/pause-stop-hide.html)
- [Digital A11y Guide](https://www.digitala11y.com/understanding-sc-2-2-2-pause-stop-hide/)
