# react-useanimations: animated SVG icons that already know how to move

> react-useanimations is the official React component for useAnimations, a set of 300 animated icons rendered by a built-in 8 kB gzipped player with no runtime dependencies. Each icon is its own module, carries a default interaction, and can also be used as a shadcn/ui registry component or as a wrapper for your own Lottie JSON.

**useAnimations/react-useanimations** — React-useanimations is a collection of free animated open source icons for React.js.

- Repository: https://github.com/useAnimations/react-useanimations
- Website: http://useanimations.com
- Stars: 1,252 · Forks: 46
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/useanimations-react-useanimations

## The problem it solves is animation work, not icon work

Most icon libraries hand you static SVG and leave the motion to you. A spinner becomes a component with a keyframe rule, a like button becomes a state machine, a menu becomes a transform that has to be written twice because the icon opens one way and closes the other. react-useanimations takes the opposite position: the motion is authored with the icon and arrives attached to it.

The description of the project is a collection of free animated open source icons for React.js, and the site behind it, useanimations.com, is where the same set is browsed and downloaded. The point of the React package is to remove the browser from that loop for application developers. A loader loops on its own, a menu toggles between two states, a trash can opens on hover, and a social icon animates while the pointer is on it, with no per-icon JavaScript written by the person using it.

Who it fits is a React developer with a product that needs a dozen or so animated icons rather than a design system of five hundred. The scope is deliberately narrow. It does not generate animation, it does not give you a timeline editor, and it does not try to be a general purpose motion library. The catalogue is 300 icons, each one a small package in its own right, and the README is explicit that a developer picks the icon and inherits the interaction that comes with it.

## A built-in player with no dependencies, one module per icon

The mechanism is a small player that ships with the package. The README states that the built-in player is 8 kB gzipped, that an icon is 2 kB on median, and that your bundle includes only the icons you import. There are no runtime dependencies listed in `package.json`; the only peer dependency is `react` at `>=18`, and the repository is TypeScript first with the types source in `src/index.tsx`.

The important detail is the import path. Every icon is its own module under `react-useanimations/lib/`, so a bundler that resolves imports statically drops the other 299 icons out of the output. The component itself is the default export, and the package also exposes it as the named exports `UseAnimations` and `UseAnimation`, the latter being the name the shadcn registry uses.

Rendering is SVG rather than a raster or video format, which is what makes the colour behaviour work. Icons follow `currentColor`, so `className="text-blue-600"`, Tailwind utility classes and plain CSS all apply without a separate prop, and the `strokeColor` and `fillColor` props are there when you need to override that per instance. The README also notes that React 18 and 19, StrictMode, the Next.js App Router and server rendering are supported, and that no `dynamic(..., { ssr: false })` wrapper is required.

## Installing the package and rendering the first icon

The install is a single npm command, and the README is explicit that the icon is a separate import rather than a prop pointing at a name string.

```bash
npm install react-useanimations
```

A minimal component then passes the imported animation into the `animation` prop.

```jsx
import UseAnimations from 'react-useanimations';
import github from 'react-useanimations/lib/github';

export default function App() {
  return <UseAnimations animation={github} size={32} />;
}
```

What you should see is the GitHub icon rendered at 32 pixels, looping while the pointer rests on it, matching the behaviour on useanimations.com. The `size` prop takes a number for pixels or any CSS length as a string, and the default is 24.

There is a barrel export for convenience, and the README attaches a warning to it that is worth reading before you use it.

```javascript
import { github, heart, menu } from 'react-useanimations/icons';
```

Production builds still include only the icons used, but the README warns that `react-useanimations/icons` loads every icon when the dev server or the test runner does not tree-shake. The recommended form for those environments is the per-icon path `react-useanimations/lib/<name>`. If you use the barrel in a Vitest or Jest run and your suite suddenly carries a few hundred kilobytes of unused animation data, this is the reason, and switching to the per-icon import is the fix.

## Six interaction modes, and a controlled toggle that does not self-toggle

Each icon arrives with the interaction it has on useanimations.com, and the `interaction` prop can override that choice. The available values are `hover-replay`, `click-replay`, `click-toggle`, `loop`, `hover` and `hover-loop`, and the difference between the hover modes is the part that usually decides the choice: `hover` plays forward on hover and backward on leave, while `hover-loop` loops while hovered and finishes the cycle when the pointer leaves.

```jsx
<UseAnimations animation={download} interaction="hover" />
```

The `click-toggle` mode has a wrinkle that the props table documents carefully. For a two state icon such as a menu or a heart, the `active` prop is controlled, so `true` shows the end state. The README states plainly that clicks do not toggle it, which means the state has to be moved in your own `onClick` handler. Forgetting that produces a button that appears to do nothing, and it is the most likely first confusion for anyone wiring a toggle icon into a form.

Two more props tune playback. `speed` defaults to 1 and scales playback, and `autoplay` defaults to `true` for looping icons unless the user prefers reduced motion. The `render` prop takes a render prop for a custom wrapper, so the icon can be dropped inside a real button element rather than the default `span` wrapper. Any other prop, including `className`, `aria-label`, `onClick` and `onMouseEnter`, is forwarded to that wrapper.

## The shadcn registry route and the own-Lottie escape hatch

There are two ways to take an icon into a project, and they lead to different maintenance stories.

The first is the ordinary npm import described above, where the package stays a dependency and the icon is referenced by module path. The second is the shadcn/ui registry. Every icon is published as a registry entry, and the CLI adds a ready-made component to your project and installs `react-useanimations` alongside it.

```bash
npx shadcn@latest add https://useanimations.com/r/checkmark.json
```

The result is a component in your own source tree, named by the registry rather than by the package convention.

```tsx
import { AnimatedCheckmark } from '@/components/animations/checkmark';

<AnimatedCheckmark size={24} />;
```

The difference in approach is ownership. The registry route copies the code into your repository, so you can edit it, and you take on the consequence of keeping a local copy in step with upstream. The npm route keeps a single source of truth and lets version bumps handle it. Projects that already standardise on the shadcn CLI tend to prefer the registry path for that reason, and the registry name `AnimatedCheckmark` explains why the package exports a second component alias.

The library also accepts animations it did not ship. The `animation` prop takes either an imported icon or an object of `{ animationData, interaction }` for your own Lottie JSON, which means a bespoke animation can travel through the same player and the same props as a catalogue icon.

## Accessibility handling that is built in rather than bolted on

An icon set is only as good as its behaviour for people who cannot use it in the usual way, and this one has answers for the common cases. Icons are decorative by default and become labelled when you pass `aria-label`, which is the right default for a chevron next to visible text and the wrong one for a button that only contains an icon. Hover animations also play on keyboard focus, but only when the icon or its wrapper is focusable, so a focusable wrapper is a requirement rather than an option if you want keyboard users to see the motion.

Touch screens are handled separately. The README states that hover animations ignore taps on touch screens, since there is no meaningful hover state on a phone and firing a full animation on every tap would be noise.

The `prefers-reduced-motion` case is handled in two places at once. The `autoplay` default for looping icons is disabled when reduced motion is preferred, and the accessibility summary in the README states that the icons are still when the user prefers reduced motion. The most recent releases make this worth checking rather than assuming: v3.0.0, v3.1.0 and v3.1.1 all shipped on 2026-10-11, and the last push to the repository was on 2026-10-13.

## Where the trade-offs sit, and what the repository does not document

The limitations are mostly about the catalogue and the packaging rather than the code. The set is 300 icons, so a design system that needs a specific brand mark or a dense utility set will not find it here, and there is no stated mechanism for submitting or adding icons beyond the scripts and icons directories in the repository. The `package.json` also carries `"private": true` alongside a published npm package name, which is an unusual combination in a manifest and is worth noting if you mirror the package internally.

The header links to an Upgrading from v2 section, so the project acknowledges the upgrade path, but the details live on the documentation site rather than in the repository. If you are pinned to v2 in an existing codebase, you need to read that page before the v3 line.

The build tooling is another practical consideration. The scripts run through `vite-plus` (`vp pack`, `vp check`, `vp test run`), the test setup uses `@vitest/browser-playwright` and `playwright`, and the `engines` field requires Node `^22.18.0 || >=24.11.0`. The `overrides` block pins `vite` to `npm:@voidzero-dev/vite-plus-core@1.1.0`, a fork published under a different scope. That is normal for a project that standardises on a patched toolchain, but if your organisation blocks non-standard npm scopes, it will not install. The licence is MIT, so the code and the icons can be used and modified in commercial products without a separate agreement.

## Conclusion

Adopt react-useanimations if you want animated icons in React without pulling in a Lottie runtime, since the player is bundled and every icon arrives with a defined interaction, a `currentColor` stroke and reduced-motion handling built in. Do not adopt it if your project standardises on the shadcn registry for everything, since the registry route copies the component into your repository and duplicates that decision, or if you need icons outside the 300 the set provides. Before installing, confirm that `react-useanimations/lib/<name>` imports work in your bundler, because the README warns that the `react-useanimations/icons` barrel loads every icon when the dev server or test runner does not tree-shake, and check that your Node version satisfies the `^22.18.0 || >=24.11.0` range recorded in `package.json`.

## FAQ

### How do I install react-useanimations and render an icon in React?

Run `npm install react-useanimations`, import the component as the default export and import the icon from its own module, then pass the icon through the `animation` prop. The README example uses `import github from 'react-useanimations/lib/github'` and renders `<UseAnimations animation={github} size={32} />`.

### Does react-useanimations add any npm dependencies to my app?

The README describes the package as having zero dependencies, with a built-in 8 kB gzipped player that renders the icons as SVG. The only peer dependency recorded in `package.json` is `react` at `>=18`.

### Why is my whole icon set being bundled when I import from react-useanimations/icons?

The README warns that `react-useanimations/icons` loads every icon when your dev server or test runner does not tree-shake, and recommends the per-icon path `react-useanimations/lib/<name>` for those environments. Production builds still include only the icons you use.

### How do I make a click-toggle icon such as a menu or heart change state?

The `active` prop is controlled for `click-toggle` icons, so `true` shows the end state, and the README states that clicks do not toggle it. You move the state yourself in your `onClick` handler.

### Can react-useanimations play my own Lottie animation?

Yes. The `animation` prop accepts either an imported icon or an object of `{ animationData, interaction }` for your own Lottie JSON, and that animation plays through the same player and the same props.

### Does the library respect prefers-reduced-motion?

The README states that the icons are still when the user prefers reduced motion, and the props table notes that `autoplay` defaults to `true` for looping icons unless reduced motion is preferred.

## Sources

- [License: MIT](https://github.com/useAnimations/react-useanimations/blob/main/LICENSE)
- [Project website](http://useanimations.com)
- [README](https://github.com/useAnimations/react-useanimations/blob/main/README.md)
- [Releases](https://github.com/useAnimations/react-useanimations/releases)
- [useAnimations/react-useanimations on GitHub](https://github.com/useAnimations/react-useanimations)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/useanimations-react-useanimations
