Contributing Code
To contribute to the Iconiq library, follow the steps below.
Important
Iconiq only accepts contributions based on Lucide icons. Pull requests containing custom icons or icons from other packs will be closed.
Animation quality: PRs with simple path length animations (strokeDasharray/strokeDashoffset "drawing" effect) will likely be rejected. We want creative, purposeful animations that enhance the icon.
We welcome contributions. Please follow these steps:
1. Fork and clone
Fork the repository on GitHub, then clone your fork:
git clone https://github.com/edwinvakayil/iconiq.gitNavigate to the project and create a branch:
cd iconiq
git checkout -b your-branch-name2. Install dependencies
Iconiq uses pnpm:
pnpm install3. Create your animated icon
- In
/icons/, create a new file with the icon name in lowercase and hyphens (e.g.heart-icon.tsx,arrow-up.tsx). - Use the template below. Replace
[YourIconName]with your icon name in PascalCase, and replace the SVG comment with the path from lucide.dev. - Add your animation logic using Framer Motion's
motioncomponents and thecontrolsobject.
'use client';
import { useAnimation } from 'motion/react';
import type { HTMLAttributes } from 'react';
import { forwardRef, useCallback, useImperativeHandle, useRef } from 'react';
import { cn } from '@/lib/utils';
export interface [YourIconName]IconHandle {
startAnimation: () => void;
stopAnimation: () => void;
}
interface [YourIconName]IconProps extends HTMLAttributes<HTMLDivElement> {
size?: number;
}
const [YourIconName]Icon = forwardRef<[YourIconName]IconHandle, [YourIconName]IconProps>(
({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {
const controls = useAnimation();
const isControlledRef = useRef(false);
useImperativeHandle(ref, () => {
isControlledRef.current = true;
return {
startAnimation: () => controls.start('animate'),
stopAnimation: () => controls.start('normal'),
};
});
const handleMouseEnter = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
if (!isControlledRef.current) {
controls.start('animate');
} else {
onMouseEnter?.(e);
}
},
[controls, onMouseEnter]
);
const handleMouseLeave = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
if (!isControlledRef.current) {
controls.start('normal');
} else {
onMouseLeave?.(e);
}
},
[controls, onMouseLeave]
);
return (
<div
className={cn(className)}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
{...props}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
{/* your svg code here */}
</svg>
</div>
);
}
);
[YourIconName]Icon.displayName = '[YourIconName]Icon';
export { [YourIconName]Icon };4. Add your icon to the icon list
Open icons/index.ts. Import your icon and add it to the top of ICON_LIST:
import { [YourIconName]Icon } from './[icon-name]';
// Add at the top of ICON_LIST:
{
name: '[icon-name]',
icon: [YourIconName]Icon,
keywords: ['keyword1', 'keyword2', 'keyword3'],
},Use the exact name and keywords from lucide.dev for your icon.
5. Update the registry
For new icons, run:
pnpm run gen-cliThis syncs your icon to the registry for the shadcn CLI.
6. Build and test
pnpm build
pnpm lint7. Commit and open a pull request
git commit -m "Add [icon-name] animated icon"
git push origin your-branch-nameOpen a pull request on the original repository with a clear description of the icon and animation.
Thank you for contributing to Iconiq!