Skip to content

[Feature Request] Reduced-motion override #252

@J-Sek

Description

@J-Sek

related to vuetify#22159

The request: add global config so users (and apps) can override prefers-reduced-motion, exposed via a hook (useReducedMotion()) and a data attribute on <body> for CSS.

Does it fit v0?

v0 already ships usePrefersReducedMotion() utility and the plugin would be a natural extension.

What needs to be covered

  • new plugin - similar to useTheme (in how it resolves prefers-color-scheme)
  • transition tokens that read the resolved value (expected in Paper or Vuetify)

Logic input value: mode: 'system' | 'always' | 'never' (reactive).

  • 'system' means resolving media query - same challenge with SSR as for adapting to "system" theme (requires client-hints)
  • 'always'/'never' - user/app preference

Paper/Vuetify are meant to consume the reduced boolean flag

  • JS-based animations could pick the readonly ref from composable or provide/inject
  • CSS-based transitions could be branch out behind [data-reduced-motion="reduce"] to either apply fade in/out or skip transition entiely

Challenges / limitations

  • CSS coordination v0 is headless, so the behavior is just a flag. Anything that actually drops a transition lives in Paper / Vuetify / app CSS. The plugin only sets the attribute; consumers must author @media (prefers-reduced-motion: reduce) and selectors.
  • Granularity ON/OFF [data-reduced-motion="reduce"] and const { current } = useReducedMotion() are meant to be consumed/translated into "keep fades, drop transforms" semantics. VPaper or SCSS/CSS tokens could define the policy.
  • SSR + hydration first paint may still flicker unless the app injects tokens server-side
  • Naming: system/always/never (clearer than in Motion user/always/never)

Recommendation

Land useReducedMotion in v0 as a createPlugin-style provider (mirroring useTheme), exposing { mode, reduced, current } and side-effecting document.body.dataset.reducedMotion. Keep policy (what to fade, what to drop) in Paper/Vuetify. The Vuetify-side regression that prompted the issue (v3.10.0) is a separate fix that consumes this primitive.


Sources:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions