Skip to content
Docs · 11 pages

Docs / Checks

Accessibility

The reduced-motion policy every component follows, and the details screen readers care about.

2 min readThis page as MarkdownSource on GitHub

Reduced motion

Every component has a prefers-reduced-motion: reduce branch, and the test suite refuses a component without one. The policy is cross-fade instead of movement, never a hard cut, never nothing:

  • Reveal and SplitText keep a fast opacity fade and drop translate, scale, blur and stagger.
  • RotatingText crossfades in place instead of rising.
  • Typewriter shows the full text at once; the caret stops blinking.
  • Marquee stops, hides its duplicate copies, and becomes a scrollable strip so every item is reachable.
  • Aurora becomes a static gradient.

Scripts read the preference through the runtime’s prefersReducedMotion() and shorten motion to near-zero rather than skipping the code path, so end states still apply.

Previewing reduced motion

The header of this site has a motion switch. It sets data-ma-motion="reduce" on <html>, and every reduced-motion rule on the page (the components’, Tailwind’s motion-reduce: utilities, the site’s own) also applies under that attribute, so the switch shows what the media query does without changing an OS setting. The exception is motion that only a (prefers-reduced-motion: no-preference) block turns on: the attribute does not stop it. Nothing is duplicated by hand: the integration’s motionAttribute option mirrors the @media (prefers-reduced-motion: reduce) blocks at build time, and prefersReducedMotion() in the runtime reads the attribute as well as the media query. Turn it on in your own project with

moonarc({ motionAttribute: true })

and stamp the attribute from a toggle of your own. It costs a few percent of CSS and no JavaScript.

Content is never hidden by default

Server HTML is the end state. Entrance effects hide content only behind html[data-ma-js], which the integration sets just before first paint. If JavaScript fails or is disabled, the page is simply visible.

Text components

SplitText and Typewriter keep the whole string in a visually hidden copy (.ma-sr) and mark the animated parts aria-hidden, so assistive tech reads one string rather than a stream of letters. RotatingText’s hidden copy lists every word once. Marquee’s duplicate copies are aria-hidden and inert, so their links are not reached twice. Aurora is aria-hidden outright.

Pointer gating

Hover effects are gated on (hover: hover) and (pointer: fine) so touch devices never trigger them on tap.