Skip to main content
CodeRocket
Accessibilityhighmedia

Avoid autoplaying media

rule · autoplay-media

Autoplaying media disrupts screen readers and startles users. Always require user interaction to start audio.

Code Example

HTML
<!-- ❌ Bad: Autoplay with audio -->
<video autoplay src="video.mp4"></video>
 
<!-- ✅ Acceptable: Autoplay muted (background video) -->
<video autoplay muted loop playsinline src="hero-bg.mp4"></video>
 
<!-- ✅ Best: No autoplay, user controls -->
<video controls src="video.mp4">
  <track kind="captions" src="captions.vtt" srclang="en" label="English">
</video>

Why It Matters

Autoplaying audio drowns out screen reader speech, startles users, and wastes bandwidth—providing user control is essential for accessibility and good UX.

Accessible Video Player

TSX
function VideoPlayer({ src, poster }) {
  const [isPlaying, setIsPlaying] = useState(false)
  const [isMuted, setIsMuted] = useState(true)
  const videoRef = useRef<HTMLVideoElement>(null)
 
  const togglePlay = () => {
    if (videoRef.current) {
      if (isPlaying) {
        videoRef.current.pause()
      } else {
        videoRef.current.play()
      }
      setIsPlaying(!isPlaying)
    }
  }
 
  return (
    <div className="video-container">
      <video
        ref={videoRef}
        src={src}
        poster={poster}
        muted={isMuted}
        playsInline
      />
 
      <div className="controls">
        <button
          onClick={togglePlay}
          aria-label={isPlaying ? 'Pause video' : 'Play video'}
        >
          {isPlaying ? <PauseIcon /> : <PlayIcon />}
        </button>
 
        <button
          onClick={() => setIsMuted(!isMuted)}
          aria-label={isMuted ? 'Unmute video' : 'Mute video'}
        >
          {isMuted ? <MutedIcon /> : <VolumeIcon />}
        </button>
      </div>
    </div>
  )
}

Background Video with Stop Button

TSX
function HeroWithVideo() {
  const [isPlaying, setIsPlaying] = useState(true)
  const videoRef = useRef<HTMLVideoElement>(null)
 
  const toggleVideo = () => {
    if (videoRef.current) {
      if (isPlaying) {
        videoRef.current.pause()
      } else {
        videoRef.current.play()
      }
      setIsPlaying(!isPlaying)
    }
  }
 
  return (
    <section className="hero">
      <video
        ref={videoRef}
        autoPlay
        muted
        loop
        playsInline
        className="hero-video"
      >
        <source src="hero.mp4" type="video/mp4" />
      </video>
 
      {/* Prominent pause control */}
      <button
        onClick={toggleVideo}
        className="video-control"
        aria-label={isPlaying ? 'Pause background video' : 'Play background video'}
      >
        {isPlaying ? 'Pause' : 'Play'} Background
      </button>
 
      <div className="hero-content">
        <h1>Welcome</h1>
      </div>
    </section>
  )
}

WCAG Requirements

CriterionRequirement
1.4.2 Audio ControlAudio that plays automatically for more than 3 seconds must have pause/stop/mute controls
2.2.2 Pause, Stop, HideMoving content must have a mechanism to pause, stop, or hide

Exceptions

  • Evaluate the rendered experience before treating a static-code smell as a blocker; interaction timing, browser behavior, and assistive technology output often determine severity.
  • Not every secondary accessibility issue deserves equal weight; prioritize the issue that most directly blocks perception, operation, or understanding.
  • Avoid adding redundant markup or ARIA solely to satisfy a rule when a simpler semantic implementation would eliminate the issue entirely.

Standards

  • Align the implementation with W3C WAI: WCAG Overview and verify the rendered experience, not only the source code.
  • Align the implementation with MDN: Accessibility and verify the rendered experience, not only the source code.

Verification

Automated Checks

  • Use browser accessibility tooling, axe, Lighthouse, or equivalent automated checks against a representative rendered state.

Manual Checks

  • Load page and verify no unexpected audio plays
  • If video autoplays, confirm it's muted
  • Check pause controls are keyboard accessible (early in tab order)
  • Verify screen reader can announce and interact with controls