Get Started

How animated icons work, whatever the icon library. Each icon is a .vue file in your project, animated by one small core from @animate-ui/vue.

Installation

Add icons one by one from your icon library's page (Lucide Icons or Hugeicons), here Lucide's Bell. Each icon is a file in your project; the core that animates them comes from @animate-ui/vue/icons, which the CLI installs with the first icon.

npx shadcn-vue@latest add https://animate-ui.com/r/vue/icons-lucide-bell.json
pnpm dlx shadcn-vue@latest add https://animate-ui.com/r/vue/icons-lucide-bell.json
yarn dlx shadcn-vue@latest add https://animate-ui.com/r/vue/icons-lucide-bell.json
bun x shadcn-vue@latest add https://animate-ui.com/r/vue/icons-lucide-bell.json

Usage

An icon animates on its own trigger:

<script setup lang="ts">
import Bell from '@/components/animate-ui/icons/Bell.vue';
</script>

<template>
  <Bell animate-on-hover />
</template>

Or let a parent decide, so hovering a whole button animates its icon:

<script setup lang="ts">
import { AnimateIcon } from '@animate-ui/vue/icons';
import Bell from '@/components/animate-ui/icons/Bell.vue';
</script>

<template>
  <AnimateIcon animate-on-hover as-child>
    <button><Bell /> Notifications</button>
  </AnimateIcon>
</template>

Icons inside an AnimateIcon inherit its props and can override them individually.

Triggers

  • animate: animates while true (or plays the named animation).
  • animate-on-hover: animates while the pointer is over the icon, and returns to rest when it leaves. A touch doesn't play it (a finger can't leave): add animate-on-tap for touch screens.
  • animate-on-tap: animates while pressed, and returns to rest on release or when the pointer leaves. Add complete-on-stop to always finish the animation.
  • animate-on-view: plays when the icon scrolls into view (animate-on-view-margin, animate-on-view-once).

Animations

Every icon has a default animation, often a few named ones, plus path (draws the strokes) and path-loop. Pick one with animation; the Lucide Icons and Hugeicons pages list each icon's. Icons drawing their strokes add one small CSS rule to the page themselves, so their paths rest solid: no Tailwind setup needed.

<ArrowRight animate-on-hover animation="pointing" />

Timing

  • speed: playback rate (2 is twice as fast). At 1, the default, icons play exactly as authored. It follows AnimateUIProvider's tempo.
  • delay: milliseconds before the animation starts.
  • loop, loop-delay: repeat, with a pause between iterations. Off screen, a loop waits after its current lap until the icon is back in view.

Persistence

  • persist-on-animate-end: stay in the animated state when it ends.
  • initial-on-animate-end: jump back to the initial state, without transition, when it ends.
  • complete-on-stop: finish the current animation before returning to rest.
  • :initial="false": mounted while animate is on, show its end state at once instead of playing it (a sidebar's trigger icon, closed from the start).

Under reduced motion, icons don't animate.

How an icon is written

Each icon is a single-file component: its animations (the same as the React icon's, exported from a plain <script>) and an IconWrapper whose slot draws the SVG with the variants of the animation playing, the controls that play them, the size and the attrs you passed.

API Reference

PropTypeDefault
size?
number28
animation?
'default' | 'path' | 'path-loop' | string'default'
animate?
boolean | stringfalse
animate-on-hover?
boolean | stringfalse
animate-on-tap?
boolean | stringfalse
animate-on-view?
boolean | stringfalse
animate-on-view-margin?
string'0px'
animate-on-view-once?
booleantrue
speed?
number1
delay?
number0
loop?
booleanfalse
loop-delay?
number0
persist-on-animate-end?
booleanfalse
initial-on-animate-end?
booleanfalse
complete-on-stop?
booleanfalse
initial?
booleantrue

AnimateIcon takes the same props (except size), plus as-child to animate through its child element.

Built by Skyleen. The source code is available on GitHub.

Last updated: 10/23/2026