Motion for the components you already have
180 effects across 13 categories. Each one is a CSS class you put on a WunderUI component — no provider, no hook, nothing to initialise, and nothing added to your JavaScript bundle.
Install
One package, one import, one CSS file. It ships no JavaScript.
npm install @wunderui/motion/* your Tailwind entry point, after the WunderUI tokens */
@import "tailwindcss";
@import "@wunderui/react/styles.css";
@import "@wunderui/motion";Use it
Two classes, and both do a job. wm is the marker the trigger and reduced-motion rules hook into; wm-<effect> is the effect.
import { Button } from "@wunderui/react"
<Button className="wm wm-halo-ring">Pro plan</Button>An effect class on its own still animates, but it will not obey the trigger attribute and it will not stop for prefers-reduced-motion. Use both.
Triggers
One attribute decides when an effect runs.
{/* loops */}
<Badge className="wm wm-sweep-rim">Live</Badge>
{/* runs only while hovered or keyboard-focused */}
<Button className="wm wm-comet-rim" data-wm="hover">Hover me</Button>
{/* one pass, then it holds its end state */}
<Card className="wm wm-prism-card" data-wm="once">…</Card>hover removes the animation rather than pausing it. A paused animation rests wherever it happened to be, which reads as a rendering bug; removing it puts the element back in its own base state.
Retuning an effect
Every effect reads the same custom properties, so you change speed and colour without forking the CSS.
| Property | Default | What it does |
|---|---|---|
| --wm-duration | per effect | length of one pass |
| --wm-accent | #12AFF0 | leading colour |
| --wm-accent-2 | #555CF3 | second colour |
| --wm-accent-3 | #FE6BBA | third colour |
| --wm-surface | var(--card) | the opaque fill behind a rim effect |
| --wm-ring | 2px | rim thickness |
<Card
className="wm wm-prism-card"
style={{ "--wm-duration": "8s", "--wm-accent": "var(--brand-primary)" }}
>
…
</Card>What it costs you
The badge on every card is the dependency cost, stated on the card and not after the install.
What else you need
Nothing beyond the stylesheet for most of the set. These are the exceptions, and they are the whole list.
- Tailwind CSS v4 is not required. The effects are plain CSS and work in any stylesheet. The import line above uses the Tailwind entry point only because that is where the WunderUI tokens already are.
- A handful of effects need a little JavaScript. The ones marked CSS + a few lines read pointer coordinates into two custom properties, or step a glyph timer. The code is on the effect's own page — it is not hidden in a package.
- Motion for React is an optional peer. Nothing in this package imports it. It earns its place when an animation has to be interruptible mid-flight, follow a gesture, or survive a layout change — a CSS keyframe cannot do any of those. Everything catalogued here can be done without it.
- Reduced motion is handled for you. Under
prefers-reduced-motion: reduceeverywmeffect stops and rests in its base state: a rim keeps its gradient and stops turning, a travelling light is simply not there. Nothing is hidden and no content depends on the motion.
Browser support
Where an effect needs something recent, the effect's page names the feature and the versions. The four the Borders set is built on are all Baseline.
| Feature | Status |
|---|---|
| @property | Baseline — Chrome 85, Firefox 128, Safari 16.4 |
| mask-composite | Baseline |
| offset-path | Baseline |
| conic-gradient | Baseline |
| @starting-style, transition-behavior: allow-discrete | Baseline since August 2024 — Chrome 117, Firefox 129, Safari 17.4 |
| View Transitions (same document) | Baseline since October 2025 — Firefox 144 was the last to ship it |
| animation-timeline: scroll() / view() | Not Baseline — Chrome 115, Safari 26; open in Firefox |
| interpolate-size: allow-keywords | Chromium 129 and up only |
Support checked September 2026.