Blink
Bounce
Float
Ping
Pop
Pulse
Shake
Spin
Swing
Tada
1import type { ComponentProps, SVGProps } from "react";2
3import AnimatedIcon from "@/components/ui/pxl/animated-icon";4
5function PixelarticonsAlarmClock(props: SVGProps<SVGSVGElement>) {6 return (7 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>8 <path d="M8 5h8v2H8zm0 14h8v2H8zM6 7h2v2H6zm0 10h2v2H6zM16 7h2v2h-2zm0 10h2v2h-2zM4 9h2v8H4zm14 0h2v8h-2zM4 2h2v2H4zm0 17h2v2H4zm14 0h2v2h-2zm0-17h2v2h-2zM2 4h2v2H2zm18 0h2v2h-2zm-9 5h2v4h-2zm2 4h2v2h-2z"></path>9 </svg>10 );11}12
13type Props = ComponentProps<typeof AnimatedIcon> & {14 label: string;15 description?: string;16}17
18function AnimatedIconExample({ label, description, ...props }: Props) {19 return (20 <div className="w-full max-w-md space-y-4 text-center">21 <div className="space-y-2">22 <p className="text-sm font-medium">{label}</p>23 <p className="text-sm text-muted-foreground">{description}</p>24 </div>25
26 <AnimatedIcon className="size-4 fill-current" {...props} />27 </div>28 );29
30}31
32export default function AnimatedIconPreview() {33 return (34 <div className="grid grid-cols-4 w-full gap-2">35 <AnimatedIconExample label="Blink" animation="blink" icon={PixelarticonsAlarmClock} />36 <AnimatedIconExample label="Bounce" animation="bounce" icon={PixelarticonsAlarmClock} />37 <AnimatedIconExample label="Float" animation="float" icon={PixelarticonsAlarmClock} />38 <AnimatedIconExample label="Ping" animation="ping" icon={PixelarticonsAlarmClock} />39 <AnimatedIconExample label="Pop" animation="pop" icon={PixelarticonsAlarmClock} />40 <AnimatedIconExample label="Pulse" animation="pulse" icon={PixelarticonsAlarmClock} />41 <AnimatedIconExample label="Shake" animation="shake" icon={PixelarticonsAlarmClock} />42 <AnimatedIconExample label="Spin" animation="spin" icon={PixelarticonsAlarmClock} />43 <AnimatedIconExample label="Swing" animation="swing" icon={PixelarticonsAlarmClock} />44 <AnimatedIconExample label="Tada" animation="tada" icon={PixelarticonsAlarmClock} />45 </div>46 )47}Installation
Section titled “Installation”pnpm dlx shadcn@latest add pxl-ui/registry/animated-icon
Install the following dependencies:
pnpm add motion
Copy and paste the following code into your project.
1import { motion, type TargetAndTransition } from "motion/react";2import type { ComponentProps, ComponentType, SVGProps } from "react";3
4import { cn } from "@/lib/utils";5
6const animations = {7 /**8 * pulse — Rhythmic heartbeat scale. Ideal for: likes, presence, health,9 * active states, anything that "lives".10 */11 pulse: {12 animate: {13 scale: [1, 1.2, 1, 1.15, 1],14 transition: {15 duration: 1.2,16 repeat: Infinity,17 repeatDelay: 1.5,18 ease: "easeInOut",19 },20 },21 },22
23 /**24 * shake — Urgent lateral vibration. Ideal for: alerts, errors, warnings,25 * rejections, anything that demands attention or signals danger.26 */27 shake: {28 animate: {29 x: [0, -4, 4, -4, 4, -2, 2, 0],30 rotate: [0, -6, 6, -6, 6, -3, 3, 0],31 transition: {32 duration: 0.6,33 repeat: Infinity,34 repeatDelay: 2,35 ease: "easeInOut",36 },37 },38 },39
40 /**41 * spin — Continuous rotation. Ideal for: loading, searching, processing,42 * timers, anything that implies ongoing activity.43 */44 spin: {45 animate: {46 rotate: 360,47 transition: {48 duration: 2,49 repeat: Infinity,50 ease: "linear",51 },52 },53 },54
55 /**56 * bounce — Vertical drop and rebound. Ideal for: notifications, new items,57 * arrivals, dropped pins, incoming events.58 */59 bounce: {60 animate: {61 y: [0, -8, 0, -4, 0],62 transition: {63 duration: 0.8,64 repeat: Infinity,65 repeatDelay: 1.8,66 ease: "easeOut",67 },68 },69 },70
71 /**72 * blink — Opacity fade in/out. Ideal for: idle states, standby, awaiting73 * input, eye/visibility metaphors, low-priority attention signals.74 */75 blink: {76 animate: {77 opacity: [1, 0.1, 1, 0.1, 1],78 transition: {79 duration: 1,80 repeat: Infinity,81 repeatDelay: 2,82 ease: "easeInOut",83 },84 },85 },86
87 /**88 * swing — Pendular rotation around top-center. Ideal for: bells, hanging89 * objects, bugs, anything that swings or oscillates.90 */91 swing: {92 animate: {93 rotate: [0, 18, -14, 10, -6, 3, 0],94 transition: {95 duration: 1.0,96 repeat: Infinity,97 repeatDelay: 2,98 ease: "easeInOut",99 },100 },101 },102
103 /**104 * pop — Quick overshoot scale. Ideal for: sparkles, highlights, new badges,105 * featured content, "tada" moments without full rotation.106 */107 pop: {108 animate: {109 scale: [1, 1.35, 0.9, 1.1, 1],110 transition: {111 duration: 0.5,112 repeat: Infinity,113 repeatDelay: 2.5,114 ease: "backOut",115 },116 },117 },118
119 /**120 * float — Gentle vertical drift. Ideal for: AI features, magic, resting121 * states, ambient presence, anything that feels weightless or ethereal.122 */123 float: {124 animate: {125 y: [0, -5, 0, -3, 0],126 transition: {127 duration: 3,128 repeat: Infinity,129 ease: "easeInOut",130 },131 },132 },133
134 /**135 * tada — Celebratory scale + wiggle combo. Ideal for: achievements,136 * birthdays, success moments, happy robot faces, party content.137 */138 tada: {139 animate: {140 scale: [1, 0.9, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1],141 rotate: [0, -3, 3, -3, 3, -3, 3, -3, 3, 0],142 transition: {143 duration: 1.2,144 repeat: Infinity,145 repeatDelay: 2,146 },147 },148 },149
150 /**151 * ping — Expand and fade out, like a radar pulse. Ideal for: sirens,152 * full-battery indicators, "online" dots, anything that broadcasts presence.153 */154 ping: {155 animate: {156 scale: [1, 1.4, 1],157 opacity: [1, 0, 1],158 transition: {159 duration: 1.5,160 repeat: Infinity,161 repeatDelay: 0.5,162 ease: "easeOut",163 },164 },165 },166} satisfies Record<string, { animate: TargetAndTransition }>;167
168type Animation = keyof typeof animations;169
170function AnimatedIcon({171 animation,172 className,173 icon: Icon,174 ...props175}: {176 /**177 * Icon to render.178 */179 icon: ComponentType<SVGProps<SVGSVGElement>>;180 /**181 * Name of the animation preset to apply.182 * If omitted, the icon renders statically.183 */184 animation?: Animation;185} & ComponentProps<typeof motion.span>) {186 return (187 <motion.span188 className={cn("inline-flex", className)}189 animate={animation ? animations[animation].animate : undefined}190 {...props}191 >192 <Icon aria-hidden="true" />193 </motion.span>194 );195}196
197export default AnimatedIcon;198
199export { AnimatedIcon, type Animation, animations };Update the import paths to match your project setup.
import { AnimatedIcon } from "@/components/ui/pxl/animated-icon"<AnimatedIcon animation="blink" icon={Icon}>