motion-icons-react
v1.1.0
Published
Animated React icons - The easiest way to add smooth animations to Lucide icons
Maintainers
Readme
Motion Icons React
Animated React icons. No framer-motion boilerplate. No variants. Just props.
Demo · Documentation · Why Motion Icons · Recipes
Overview
Animating icons in React is repetitive. With framer-motion, every icon needs a wrapper, a variants object, and timing config:
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0, rotate: 360 }}
transition={{ duration: 1 }}
>
<Bell />
</motion.div>Motion Icons does the same thing in one line:
<MotionIcon name="Bell" animation="spin" entrance="fadeInUp" />Features
- 3,500+ icons via Lucide React
- 19 preset animations covering loops, feedback, and entrances
- Built-in interactive states (hover, click, focus)
- Tuned animation curves and durations based on Emil Kowalski's design engineering principles
- Respects
prefers-reduced-motionautomatically - ~5 KB minified, no runtime dependencies beyond React and Lucide
- Full TypeScript types
- Declarative, prop-driven API
Installation
npm install motion-icons-react lucide-reactyarn add motion-icons-react lucide-reactpnpm add motion-icons-react lucide-reactBasic Usage
import { MotionIcon } from 'motion-icons-react';
import 'motion-icons-react/style.css';
// Looping animation
<MotionIcon name="Heart" animation="pulse" />
// Entrance on mount
<MotionIcon name="Bell" entrance="fadeInUp" />
// Interactive — hover lift, click press, keyboard focus
<MotionIcon name="ThumbsUp" animation="bounce" trigger="hover" interactive />All props are optional except name. Defaults are subtle and production-friendly.
Why Motion Icons
Compared to Framer Motion
<motion.div
animate={{ rotate: 360 }}
transition={{
duration: 1,
repeat: Infinity,
ease: "linear",
}}
>
<Loader2 size={20} />
</motion.div><MotionIcon
name="Loader2"
animation="spin"
size={20}
/>| | Motion Icons | Framer Motion | | --- | --- | --- | | Lines of code | 1 | 8+ | | Wrapper element | None | Required | | Bundle size | ~5 KB | ~30 KB | | API style | Declarative props | Imperative configuration | | Built-in animations | 19 presets | None (manual curves) |
When to use what
Use Motion Icons for animated icons: loading spinners, notification chimes, button feedback, success states, and entrance reveals.
Use Framer Motion for complex page transitions, layout animations, and gesture-driven UIs.
Animation Catalogue
Looping animations
pulse, spin, bounce, ping, wiggle, flip, heartbeat
Attention animations
shake, swing, tada, rubber
Feedback animations
press (160 ms click feedback), nudge (200 ms hover hint), success (220 ms confirmation), pop (200 ms list-insert entrance)
Entrance animations
fadeIn, fadeInUp, fadeInDown, fadeInLeft, fadeInRight, scaleIn, slideInUp, slideInDown, rotateIn, zoomIn
Props
Core
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| name | string | required | Lucide icon name |
| size | number | 24 | Icon size in pixels |
| color | string | "currentColor" | Stroke color |
| weight | "light" \| "regular" \| "bold" | "regular" | Stroke weight |
Animation
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| animation | AnimationType | "none" | Main animation |
| entrance | EntranceAnimationType \| null | null | Entrance on mount |
| trigger | "always" \| "hover" \| "click" \| "focus" | "always" | When to play |
| animationDuration | number | 1000 | Duration in ms |
| animationDelay | number | 0 | Delay in ms |
Interaction
| Prop | Type | Description |
| --- | --- | --- |
| interactive | boolean | Enables hover lift and active press feedback |
| onClick | (e) => void | Click handler |
| onMouseEnter / onMouseLeave | (e) => void | Hover handlers |
Accessibility
| Prop | Type | Description |
| --- | --- | --- |
| aria-label | string | Screen reader label (defaults to icon name) |
Recipes
Like button
const [liked, setLiked] = useState(false);
<MotionIcon
name="Heart"
animation={liked ? "heartbeat" : "none"}
color={liked ? "#ef4444" : "#6b7280"}
onClick={() => setLiked(!liked)}
interactive
/>Loading button
<button disabled={loading}>
{loading && <MotionIcon name="Loader2" animation="spin" size={16} />}
{loading ? "Submitting..." : "Submit"}
</button>Notification badge
<MotionIcon
name="Bell"
animation={unreadCount > 0 ? "wiggle" : "none"}
interactive
/>Search input
<MotionIcon
name={searching ? "Loader2" : "Search"}
animation={searching ? "spin" : "none"}
size={16}
/>Success toast
<MotionIcon
name="CheckCircle"
entrance="zoomIn"
animation="success"
color="#10b981"
/>Click feedback
<MotionIcon
name="Copy"
animation="press"
trigger="click"
onClick={handleCopy}
interactive
/>Design Principles
The animation timings, easing curves, and feedback patterns follow design engineering guidance documented at animations.dev:
- Custom easing curves over the built-in CSS keywords, which feel weak.
- Entrances start fast and use
ease-outso motion is visible the moment the user looks. - UI animations stay under 300 ms; click feedback lives in the 100–160 ms band.
- Nothing animates from
scale(0)— entrances start atscale(0.92)or higher with opacity 0. - Hover scaling is gated behind
@media (hover: hover) and (pointer: fine)so touch devices do not fire phantom hovers. - Buttons receive a
scale(0.97)press response on:active, so the interface feels responsive. prefers-reduced-motionis honoured by collapsing transforms to opacity-only fades, not by removing feedback entirely.
Accessibility
prefers-reduced-motion: looping and movement-heavy animations are disabled; entrances collapse to a 200 ms opacity fade so structural cues still appear.- Semantic markup: interactive icons render with
role="button"and a tab index; decorative icons render withrole="img". - Keyboard support:
trigger="focus"plays the animation only on:focus-visible(real keyboard focus), not on mouse clicks. - Screen readers: every icon receives an
aria-label, defaulting to the icon name.
Development
git clone https://github.com/Garvit1000/motion-icons.git
cd motion-icons
npm install
npm run devLinking locally
npm run build
npm link
# in the consuming project
npm link motion-icons-reactContributing
Contributions are welcome.
- Fork the repository
- Create a branch:
git checkout -b feature/your-feature - Commit your changes
- Push the branch and open a pull request
See CONTRIBUTING.md for details.
Support
License
MIT — see LICENSE.
Built by Garvit. If Motion Icons saves you time, please star the repository.
