Animated Icons
ProMotion for any glyph in the kit — 27 presets plus a curated default per icon, driven by the Web Animations API with no CSS file and no animation library. Five triggers (hover, click, in-view, mount, manual) and `prefers-reduced-motion` honoured before anything plays.
import { SvAnimatedIconProComponent } from '@styloviz-pro/icons';Demo & usage
Basic usage
ProUsage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
The curated motion, per glyph
Pro`animation` defaults to `default`, which resolves the motion chosen for that specific glyph — a bell rings, a trash lid tips, a check draws itself on. That is the reason to reach for this component over the directive: you get the right motion without picking one for all 687 glyphs.
A named preset, looping
ProName a preset to override the curated choice. `loop` repeats until something stops it, which is what a spinner wants and what a hover affordance does not.
Driven by your own state
Pro`trigger="manual"` hands control over. Bind `play` for a declarative state, or call `start()` / `stop()` on the component when the moment comes from an event rather than a signal.
On scroll, once
Pro`in-view` plays when the icon enters the viewport, via IntersectionObserver. `viewOnce` is on by default — an icon that re-animates every time it scrolls back into view is the thing people disable animation over. `viewMargin` starts it early.
The directive, on an icon you already have
ProThe component is `sv-icon-pro` with the directive applied and the name forwarded. Use `svAnimate` directly to animate an icon that is already placed — including a per-icon component, which has no `name` for the resolver to read, so pass `svAnimateFor` to get that glyph's curated motion.
Timing overrides
Pro`speed` scales the preset; `duration` and `easing` replace what it declares. Prefer `speed` — a preset's duration is tuned to its own keyframes, and a flat override is what makes a draw finish before the stroke has arrived.
When to use
- Giving one icon a moment of motion: a bell on a new notification, a spinner during a sync, a check when something saved.
- You want the motion that suits each glyph without choosing one per icon — `default` already resolves it.
- For a page-wide loading state use a Spinner or Skeleton; an animated icon draws the eye to one spot, which is wasted on a whole screen.
Async states
None — this component has nothing to load, so it has no loading, empty or error state to drive.
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
| namerequired | IconProName | IconName | (string & {}) | — | Icon name (free or Pro). |
| size | IconSize | 'md' | Rendered size in px, or a named token (`sm`/`md`/`lg`). |
| strokeWidth | number | 1.75 | Stroke width in viewBox units. |
| weight | IconProWeight | 'line' | Visual weight: `line` · `solid` · `sharp` · `duotone`. |
| title | string | null | null | Accessible label. When set the icon is `role="img"`; otherwise `aria-hidden`. |
| flip | IconFlip | null | Mirror the icon horizontally or vertically. |
| rotate | number | 0 | Rotate clockwise, in degrees, around the centre. |
| cssClass | string | '' | Extra CSS classes on the root `<svg>`. |
| animation | IconAnimationName | string | 'default' | Motion to play; `default` uses the glyph's curated motion. |
| trigger | SvAnimateTrigger | 'hover' | What starts the animation. |
| loop | boolean | false | Repeat until stopped. |
| play | boolean | false | Controlled play state — used when `trigger="manual"`. |
| delay | number | 0 | Start delay in ms. |
| speed | number | 1 | Playback rate multiplier. |
| duration | number | null | null | Override the motion's duration in ms. |
| easing | string | null | null | Override the motion's easing. |
| persist | boolean | false | Keep the end state after finishing. |
| viewOnce | boolean | true | For `in-view`: animate only once. |
| viewMargin | string | '0px' | For `in-view`: IntersectionObserver root margin. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| animationStart | string | Emits the resolved motion key when playback starts. |
| animationDone | string | Emits the resolved motion key when a non-looping playback finishes. |
Customization & theming
- Pick the motion with `animation` — `default` for the glyph's curated choice, or one of 27 presets (`draw`, `draw-loop`, `pulse`, `spin`, `spin-ccw`, `spin-slow`, `beat`, `ring`, `swing`, `wobble`, `jello`, `tada`, `shake`, `flash`, `blink`, `pop`, `bounce`, `float`, `flip`, `sweep`, `fly`, `hinge`, `rotate-in`, `nudge-right`, `nudge-left`, `nudge-up`, `nudge-down`).
- Choose what starts it with `trigger` (hover · click · in-view · mount · manual); with `manual`, bind `play` or call `start()` / `stop()`.
- Shape the timing with `delay`, `speed`, `duration` and `easing`; `loop` repeats and `persist` keeps the end state instead of resetting.
- Tune `in-view` with `viewOnce` and `viewMargin` (an IntersectionObserver root margin).
- Everything `sv-icon-pro` takes is forwarded: `name`, `size`, `weight`, `strokeWidth`, `title`, `flip`, `rotate` and `cssClass`.
- React to `animationStart` / `animationDone` — both emit the RESOLVED motion key, so a handler can tell which motion `default` picked.
- Apply `svAnimate` directly to any icon you have already placed; pass `svAnimateFor` when the icon is a per-icon component with no `name` for the resolver to read.
Best practices
- Do: Leave `animation="default"` unless you have a reason. The per-glyph choices are curated, and a generic `pulse` on everything reads as a page that is merely busy.
- Do: Set `title` on an icon whose motion is the status — a spinning glyph that says nothing announces nothing, and the motion is exactly the information a screen-reader user cannot see.
- Do: Reserve `loop` for state that is genuinely ongoing (syncing, recording). A looping decoration never stops competing with the content beside it.
- Tip: Scale timing with `speed` rather than replacing `duration`; each preset's duration is tuned to its own keyframes.
- Don't: Don't use motion as the only signal that something changed. `prefers-reduced-motion` suppresses playback entirely, so anyone on that setting sees a static icon and no state at all.
- Don't: Don't animate more than one or two icons in a view. The point of motion is that it is the only thing moving.
Accessibility
- `prefers-reduced-motion: reduce` suppresses playback entirely — the icon renders in its resting state rather than playing a shortened version, because a smaller amount of the thing that triggers vestibular symptoms is still that thing.
- Motion never carries meaning on its own. Set `title` when the animation IS the status: it names the glyph `role="img"`, which is the only part of a spinning icon that reaches a screen reader.
- Playback is Web Animations API only, with no CSS keyframes and no library, so it degrades to a static icon under SSR and on any runtime without WAAPI instead of throwing.
- The animation runs on transforms and stroke properties, so it never moves the glyph out of its box and never reflows the text beside it.
- `animationDone` fires with the resolved motion key on non-looping playback, so a host can wait for the motion to finish before moving focus rather than guessing at a duration.
Feedback on Animated Icons
Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.