Prerequisites
Before adding a new icon, ensure you have:- Cloned the Anicon repository
- Installed dependencies with
npm install - Familiarity with React and Motion (formerly Framer Motion)
Step-by-Step Process
Create a new folder for your icon under
registry/default/. Follow the naming convention icon-[name]:"use client";
import { motion, useReducedMotion } from "framer-motion";
export interface IconMyIconProps extends React.SVGProps<SVGSVGElement> {
size?: number;
strokeWidth?: number;
}
const animationVariants = {
rest: { scale: 1 },
hover: {
scale: 1.1,
transition: {
duration: 0.5,
repeat: Infinity,
repeatType: "reverse",
ease: "easeInOut"
}
}
};
export function IconMyIcon({
size = 24,
strokeWidth = 2,
className,
...props
}: IconMyIconProps) {
const { onAnimationStart, ...rest } = props;
const prefersReducedMotion = useReducedMotion();
return (
<motion.svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeLinejoin="round"
initial={prefersReducedMotion ? false : "rest"}
animate={prefersReducedMotion ? false : "rest"}
whileHover={prefersReducedMotion ? undefined : "hover"}
whileTap={prefersReducedMotion ? undefined : "tap"}
className={`outline-none focus:outline-none focus:ring-0 select-none ${className ?? ""}`.trim()}
variants={animationVariants}
{...rest}
>
{/* Your SVG paths here */}
<motion.path d="M..." />
</motion.svg>
);
}
Always use
"use client" directive at the top since Motion components require client-side rendering.{
"name": "icon-my-icon",
"type": "registry:component",
"title": "Animated My Icon",
"description": "Short description of what the icon does.",
"dependencies": ["motion"],
"files": [
{
"path": "registry/default/icon-my-icon/icon-my-icon.tsx",
"type": "registry:component"
}
]
}
name: The icon identifier (must match folder name)type: Always "registry:component"title: Display name (typically “Animated [Icon Name]”)description: Brief description of the animation behaviordependencies: Always include "motion"files: Array with path to your component fileOpen http://localhost:3000 to see your icon in the showcase.
Best Practices
Accessibility
- Always check for reduced motion preferences using
useReducedMotion() - Disable animations when
prefersReducedMotionis true - Use semantic props like
aria-labelwhen needed
Performance
- Keep animations lightweight and performant
- Use Motion’s optimized properties (
x,y,scale,rotate,opacity) - Avoid animating properties that trigger layout recalculation
Naming Conventions
- Use kebab-case for folder and file names:
icon-my-icon - Use PascalCase for component names:
IconMyIcon - Keep names descriptive but concise
Animation Design
- Make animations subtle and purposeful
- Use the
animationConfighelper fromlib/animation-config.tsfor consistency - Test animations at different sizes and stroke widths
Example: Adding a Pulse Icon
Here’s a complete example of adding a pulse icon: 1. Create folder and file:icon-pulse.tsx):
registry.json:
Next Steps
- Learn about creating custom animations
- Understand the registry build process
- Explore Motion documentation for advanced animations