Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.

Provide instant anchor scroll option

Smooth scroll animations to anchor links respect motion preferences or provide an instant alternative.

Utilities
Quick take
Typical fix time 10 min
  • Disable smooth scroll when prefers-reduced-motion is set
  • Use CSS scroll-behavior: smooth with media query check
  • Ensure focus moves to anchor target for keyboard users
  • Provide instant scroll as default or fallback
Why it matters: Smooth scroll animations can trigger vertigo, nausea, and disorientation for users with vestibular disorders—instant navigation is safer and often faster.

Rule Details

Smooth scrolling should respect motion preferences to avoid triggering vestibular disorders.

Code Example

/* ❌ Bad: Always smooth, ignores preferences */
html {
  scroll-behavior: smooth;
}
 
/* ✅ Good: Respect motion preferences */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}
 
/* Users who prefer reduced motion get instant scrolling (default) */

Why It Matters

Smooth scroll animations can trigger vertigo, nausea, and disorientation for users with vestibular disorders—instant navigation is safer and often faster.

JavaScript Approach

function scrollToElement(elementId: string) {
  const element = document.getElementById(elementId)
  if (!element) return
 
  const prefersReducedMotion = window.matchMedia(
    '(prefers-reduced-motion: reduce)'
  ).matches
 
  element.scrollIntoView({
    behavior: prefersReducedMotion ? 'instant' : 'smooth',
    block: 'start'
  })
 
  // Move focus to target for keyboard users
  element.focus({ preventScroll: true })
}

React Hook

function useScrollToAnchor() {
  const prefersReducedMotion = useReducedMotion()
 
  const scrollTo = useCallback((elementId: string) => {
    const element = document.getElementById(elementId)
    if (!element) return
 
    element.scrollIntoView({
      behavior: prefersReducedMotion ? 'instant' : 'smooth',
      block: 'start'
    })
 
    // Set tabindex if element isn't focusable
    if (!element.hasAttribute('tabindex')) {
      element.setAttribute('tabindex', '-1')
    }
    element.focus({ preventScroll: true })
  }, [prefersReducedMotion])
 
  return scrollTo
}
 
function useReducedMotion() {
  const [prefersReduced, setPrefersReduced] = useState(false)
 
  useEffect(() => {
    const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
    setPrefersReduced(mediaQuery.matches)
 
    const handler = (e: MediaQueryListEvent) => setPrefersReduced(e.matches)
    mediaQuery.addEventListener('change', handler)
    return () => mediaQuery.removeEventListener('change', handler)
  }, [])
 
  return prefersReduced
}
interface AnchorLinkProps {
  href: string
  children: React.ReactNode
}
 
function AnchorLink({ href, children }: AnchorLinkProps) {
  const scrollTo = useScrollToAnchor()
 
  const handleClick = (e: React.MouseEvent) => {
    if (href.startsWith('#')) {
      e.preventDefault()
      scrollTo(href.slice(1))
    }
  }
 
  return (
    <a href={href} onClick={handleClick}>
      {children}
    </a>
  )
}

Focus Management

<!-- Target must be focusable for keyboard navigation -->
<section id="features" tabindex="-1">
  <h2>Features</h2>
  <!-- Content -->
</section>
/* Hide focus ring when section is focused via anchor */
section:focus {
  outline: none;
}
 
/* But show focus for keyboard navigation */
section:focus-visible {
  outline: 2px solid var(--focus-color);
}

Exceptions

  • Simple data tables can sometimes fail more from missing header relationships than from missing enhancements such as captions or mobile wrappers, so prioritize the strongest semantic issue.
  • Do not convert layout structures into data-table markup just to satisfy a rule; the correct fix may be to remove table semantics entirely.
  • When several table-accessibility issues overlap, resolve the header-cell relationship first because downstream announcements depend on it.

Verification

Automated Checks

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

Manual Checks

  • Enable "Reduce motion" in system accessibility settings
  • Click anchor links—should scroll instantly, not smoothly
  • Verify focus moves to target section
  • Tab through page after anchor click—focus should continue from anchor target

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Click anchor links (same-page navigation) and verify smooth scrolling is disabled when prefers-reduced-motion is set. Confirm anchor navigation works correctly with keyboard and screen readers.

Fix

Auto-fix issues

Use scroll-behavior: smooth only within a prefers-reduced-motion media query check. Provide instant scrolling as the default or reduced-motion fallback. Ensure focus moves to the anchor target.

Explain

Learn more

Explain how animated scroll transitions can cause motion sickness and disorientation for users with vestibular disorders, and why instant navigation is often preferable for accessibility.

Review

Code review

Review the rendered markup and interactive states that affect Provide instant anchor scroll option. Flag exact elements, roles, labels, focus behavior, or keyboard interactions that violate the rule, and note how to verify the fix with browser accessibility tooling or assistive tech.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

axe DevTools
deque.comTool

Rules that often go hand-in-hand with this one.

Respect reduced motion preferences

Animations respect user motion preferences, avoid seizure-triggering flashing, and include warnings for excessive motion.

Accessibility
Provide alternatives to parallax effects

Parallax scrolling effects have reduced-motion alternatives or can be disabled by users.

Accessibility
Avoid scrolljacking and custom scroll behavior

Natural scroll behavior is preserved without custom scroll speeds, directions, or hijacked scroll events.

Accessibility
Prevent seizure-triggering flashing content

Content does not flash more than three times per second to prevent seizures in users with photosensitive epilepsy.

Accessibility

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385