logo svelte /motion v0.6.5

useReducedMotionConfig

useReducedMotionConfig resolves the active reduced-motion policy for the current component subtree by combining the nearest <MotionConfig reducedMotion="..."> ancestor with the OS-level prefers-reduced-motion setting.

<script>
    import { motion, useReducedMotionConfig } from '@humanspeak/svelte-motion'

    const reduced = useReducedMotionConfig()
</script>

{#if !reduced.current}
    <motion.div animate={{ x: 100 }} />
{/if}
<script>
    import { motion, useReducedMotionConfig } from '@humanspeak/svelte-motion'

    const reduced = useReducedMotionConfig()
</script>

{#if !reduced.current}
    <motion.div animate={{ x: 100 }} />
{/if}
mode · live running open

Resolved policy: no-preference

Set <MotionConfig reducedMotion="...">

Tip: Chrome DevTools → Rendering → emulate prefers-reduced-motion: reduce to verify the 'user' path honors the OS setting.

Why two hooks?

  • useReducedMotion only reads the OS preference.
  • useReducedMotionConfig reads the resolved policy — it lets a parent <MotionConfig> override the OS preference (e.g. force-disable motion in a preview pane regardless of system settings).

<MotionConfig reducedMotion>

The reducedMotion prop on <MotionConfig> controls how transform animations are handled for descendant motion elements:

ValueBehavior
'never'Default. Animations run as authored.
'always'Strip transform keys (x, y, scale, rotate, skew, …). Other props still animate.
'user'Honor the OS-level prefers-reduced-motion. Acts like 'always' when the user opted in.
<script>
    import { motion, MotionConfig } from '@humanspeak/svelte-motion'
</script>

<MotionConfig reducedMotion="user">
    <motion.div
        initial={{ x: -200, opacity: 0 }}
        animate={{ x: 0, opacity: 1 }}
        transition={{ duration: 0.6 }}
    >
        Fades in always; only translates when the user hasn't opted into reduced motion.
    </motion.div>
</MotionConfig>
<script>
    import { motion, MotionConfig } from '@humanspeak/svelte-motion'
</script>

<MotionConfig reducedMotion="user">
    <motion.div
        initial={{ x: -200, opacity: 0 }}
        animate={{ x: 0, opacity: 1 }}
        transition={{ duration: 0.6 }}
    >
        Fades in always; only translates when the user hasn't opted into reduced motion.
    </motion.div>
</MotionConfig>

Custom decisions

Use the hook directly when you want to make per-component decisions that go beyond stripping transforms — for example, swapping a parallax effect for a static background:

<script lang="ts">
    import { useReducedMotionConfig } from '@humanspeak/svelte-motion'

    const reduced = useReducedMotionConfig()
</script>

{#if reduced.current}
    <StaticHero />
{:else}
    <ParallaxHero />
{/if}
<script lang="ts">
    import { useReducedMotionConfig } from '@humanspeak/svelte-motion'

    const reduced = useReducedMotionConfig()
</script>

{#if reduced.current}
    <StaticHero />
{:else}
    <ParallaxHero />
{/if}

How it resolves

PolicyOS pref reduceOS pref no-preference
no parentfalsefalse
'never'falsefalse
'always'truetrue
'user'truefalse

API Reference

Returns

A ReducedMotionState object:

  • current boolean (getter) — true when descendant motion should be reduced (resolved policy + OS preference). Reactive via $state so reads inside templates, $derived, and $effect track changes to either source automatically.
  • subscribe(run) — Svelte readable store contract. Fires on every OS-preference change AND on every mid-tree <MotionConfig reducedMotion={...}> policy reassignment, so legacy store consumers see both sources. Kept for compat with hooks that still consume Svelte readables.

See also


Based on Motion’s MotionConfig.reducedMotion API.