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}Resolved policy: no-preference
Tip: Chrome DevTools → Rendering → emulate prefers-reduced-motion: reduce to verify the 'user' path honors the OS setting.
Why two hooks?
useReducedMotiononly reads the OS preference.useReducedMotionConfigreads 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:
| Value | Behavior |
|---|---|
'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
| Policy | OS pref reduce | OS pref no-preference |
|---|---|---|
| no parent | false | false |
'never' | false | false |
'always' | true | true |
'user' | true | false |
API Reference
Returns
A ReducedMotionState object:
currentboolean(getter) —truewhen descendant motion should be reduced (resolved policy + OS preference). Reactive via$stateso reads inside templates,$derived, and$effecttrack 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
useReducedMotion— OS preference only- WCAG 2.3.3 Animation from Interactions
Based on Motion’s MotionConfig.reducedMotion API.