Animated Icons

A motion-driven action icon set. Six glyphs — copy, share, bookmark, arrow, sparkles, undo — whose hover animation encodes the meaning of the action. Every transition is a two-state spring, so the motion is fully interruptible.

copy
share
bookmark
arrow
sparkles
undo
Customize
Icon set
20px
accent (token)

Installation

npx shadcn@latest add https://craftbits.dev/r/animated-icons.json

Usage

import { AnimatedIcon } from "@craft-bits/core";
 
<AnimatedIcon name="copy" />

Understanding the component

  1. Two-state springs, not keyframes. Every glyph animates between exactly two states — rest and hover. The spring interpolates from its current position whenever the state flips, so hovering off mid-flight reverses the motion smoothly instead of snapping back to zero.
  2. Spring tokens. Stroke draws and small scales use SPRINGS.snap. The overshoot motions (bookmark drop, undo rotation, share node pulse) use a tuned bouncy spring for that "tactile" landing.
  3. Reduced-motion fallback. When the OS-level prefers-reduced-motion is on — or paused is explicitly set — the icon renders its rest-state body with no transitions. The glyph stays legible and identifiable; only the motion disappears.
  4. ANIMATED_ICONS map. The full motion-aware glyph map is exported so consumers can iterate the set or compose custom layouts without re-listing names.

Variants / Examples

// Iterate the full set.
import { AnimatedIcon, ANIMATED_ICON_NAMES } from "@craft-bits/core";
 
{ANIMATED_ICON_NAMES.map((name) => (
  <AnimatedIcon key={name} name={name} />
))}
 
// Override the accent color used on hover / focus.
<AnimatedIcon name="sparkles" accentColor="#a855f7" />
 
// Force the static fallback (e.g. inside a print stylesheet).
<AnimatedIcon name="undo" paused />

Props

PropTypeDefaultDescription
name'copy' | 'share' | 'bookmark' | 'arrow' | 'sparkles' | 'undo'requiredWhich glyph to render.
sizenumber20Pixel diameter of the inner SVG glyph.
accentColorstringvar(--cb-color-accent)Border tint applied on hover / focus.
pausedbooleanfalseWhen true, skip animations and render the rest-state glyph.
classNamestringExtra classes merged onto the outer tile span.

Accessibility

  • The tile and inner SVG are marked aria-hidden="true" by default — these are decorative micro-interactions. If the icon stands alone as a button, wrap it in a button with an aria-label.
  • Hover and focus both trigger the animation, so keyboard users get the same affordance as pointer users.
  • usePrefersReducedMotion short-circuits every animation when the OS-level setting is on; the icon falls back to a static glyph automatically.

Credits

  • Extracted from: terminal-dreams (src/components/principles/AnimatedIcons.tsx).