F50: When Blinking Never Stops
Patricia · AI Research Engine
Analytical lens: Risk/Legal Priority
Government compliance, Title II, case law
AI-assisted · Source-linked · Editorially reviewed · Methodology
Trust note
This article was drafted with AI assistance, reviewed against accessibility.chat editorial standards, and should be treated as research and education rather than legal advice. We prioritize primary sources and correct material errors.

A script toggles visibility on and off, 450 milliseconds each cycle, indefinitely. No pause button. No timeout. Just endless motion that the user cannot stop, cannot pause, and cannot escape without leaving the page entirely.
This is WCAG 2.2 Failure F50 (opens in new window). It describes a specific, documentable failure pattern — not a gray area, not a judgment call. When a script produces a blink effect and provides no mechanism to stop it within five seconds, the implementation fails Success Criterion 2.2.2 Pause, Stop, Hide (opens in new window). The W3C's official technique catalog is unambiguous on this point.
What's worth sitting with, though, is how something this straightforward keeps appearing in production code.
The Failure
F50 applies to any technology where scripts control content visibility through toggling — turning elements visible, then hidden, then visible again in a loop. The canonical failure pattern from the W3C source looks like this:
// blink "on" statefunction show(){ document.getElementById("blink1").style.visibility = "visible"; window.setTimeout(hide, 450);}// blink "off" statefunction hide(){ document.getElementById("blink1").style.visibility = "hidden"; window.setTimeout(show, 450);}// kick it offshow();<span id="blink1">This content will blink</span>The mechanism is simple. The problem is what's absent: any path to stopping it. No clearTimeout() call triggered after five seconds. No user control. No CSS animation-iteration-count cap. The loop is self-perpetuating by design — each function calls the other, indefinitely.
SC 2.2.2 requires that for any moving, blinking, or scrolling content that starts automatically, lasts more than five seconds, and is presented in parallel with other content, users must have a mechanism to pause, stop, or hide it. Blinking content that runs indefinitely satisfies none of those conditions.
Why This Matters
The word "blink" sounds minor. It isn't.
For users with photosensitive epilepsy or photosensitive migraine disorders, rapidly alternating visual states can trigger neurological responses that range from discomfort to seizure. The 450ms interval in the example above produces roughly 1.1 blinks per second — well within ranges documented as problematic in clinical literature. The WCAG Understanding document for 2.2.2 (opens in new window) notes that blinking can be a significant barrier specifically because users cannot control it.
For users with attention-deficit conditions, persistent motion in peripheral vision competes constantly with whatever they're actually trying to read. Cognitive load increases. Task completion suffers. The blinking element doesn't need to be large to be disruptive — motion draws attention involuntarily, which is precisely why designers reach for it in the first place.
For users with vestibular disorders, even content that isn't technically "flashing" at seizure-triggering frequencies can induce dizziness, nausea, or disorientation when it persists without stopping.
None of this is speculative. These are documented, population-level effects on real users trying to access real content.
The Fix
The corrected pattern requires two additions: a timeout that stops the blinking automatically at or before five seconds, or a user-accessible control that stops it on demand. The auto-stop approach:
let blinkTimer;let stopTimer;function show(){ document.getElementById("blink1").style.visibility = "visible"; blinkTimer = window.setTimeout(hide, 450);}function hide(){ document.getElementById("blink1").style.visibility = "hidden"; blinkTimer = window.setTimeout(show, 450);}function stopBlinking(){ clearTimeout(blinkTimer); document.getElementById("blink1").style.visibility = "visible";}// Start blinking, stop automatically after 4.5 secondsshow();stopTimer = window.setTimeout(stopBlinking, 4500);Alternatively — and often better from a user-control standpoint — provide a visible button:
<button onclick="stopBlinking()">Stop blinking</button><span id="blink1">This content will blink</span>The user-control approach gives people agency rather than just limiting the duration. Both satisfy SC 2.2.2. The choice between them depends on whether the blinking serves a time-sensitive purpose (auto-stop may be appropriate) or is purely decorative (user control is almost always better).
W3C's related technique — Using scripts to control blinking and stop it in five seconds or less — covers the implementation in detail.
Applying This
Automated testing tools detect some forms of this failure, but not reliably. The core challenge is that automated tools can't always distinguish between a loop that stops and one that doesn't — especially when the blink is triggered conditionally or tied to state changes. As our research on automated testing versus manual audits documents, this is precisely the category of failure that slips through automated pipelines.
For development teams, the practical catch points are:
Code review: Flag any setTimeout/setInterval pattern that toggles visibility, opacity, or display. Ask immediately: does this stop? How?
Design review: Challenge any spec that calls for persistent animation or blinking without specifying a stop condition. The design stage is where this failure is cheapest to fix.
Manual QA: Load the page and watch. If something is still moving after five seconds with no visible control to stop it, that's a testable failure.
CSS animations: F50 addresses script-controlled blinking, but the same principle applies to CSS animation with infinite iteration count on blinking effects. Both warrant scrutiny under SC 2.2.2.
The broader pattern worth noting: F50 is one of a cluster of failures in the WCAG technique catalog that organizations tend to underweight because the effect seems cosmetic. Compliance frameworks that treat all failures as equivalent miss the distinction between a contrast ratio that's marginally off and a blinking element that triggers neurological harm. Triage matters.
CORS Perspective
From a Risk/Legal Priority lens, F50 sits in an uncomfortable position: it's a clear, documented failure against a named success criterion, which means it's straightforwardly citable in a complaint or DOJ investigation under 28 CFR Part 36 (opens in new window) (Title III) or 28 CFR Part 35 (opens in new window) (Title II) — but the community impact extends well beyond legal exposure. The question worth sitting with is this: if a failure pattern is both easy to fix and capable of causing neurological harm to real users, why does it persist in production? The answer is usually organizational, not technical — no one assigned ownership of the stop condition, or the design spec never included one. That's a capacity and process problem, not a knowledge gap, and it suggests that fixing F50 in isolation is less valuable than fixing the workflow that allowed it to ship.
About the Patricia lens
A risk and legal lens. Frames findings around regulatory exposure, drawing on Title II obligations, published case law, and government compliance requirements.
Patricia is an AI analyst lens, not a human staff member. It helps frame this article through a consistent accessibility perspective.
Specialization: Government compliance, Title II, case law
View all articles using this lens →Primary source reviewed: https://www.w3.org/WAI/WCAG22/Techniques/failures/F50 (opens in new window)
Transparency Disclosure
This article was drafted with AI assistance and reviewed against our editorial methodology. We disclose that process so readers can judge the work clearly.