CLI tool for generating crypto icon components for Next.js projects with shadcn/ui and Tailwind CSS
npm install crypto-icon-next-cliImage component for optimal performance
CryptoIcon component for all icons
CryptoIcon component accepts these props:
typescript
type CryptoIconProps = {
name: string; // Icon name (e.g., "BTC", "MetaMask", "Ethereum")
mode?: "light" | "dark"; // Display mode (default: "light")
className?: string; // Additional CSS classes
size?: number; // For square icons (default: 24)
width?: number; // Specific width (overrides size)
height?: number; // Specific height (overrides size)
alt?: string; // Alt text (default: icon name)
fallback?: React.ReactNode; // Custom fallback when icon not found
};
`
Examples:
`tsx
// Basic usage (light mode by default)
// Dark mode
// With TypeScript enums
import { TokenSymbol, WalletName } from "./components/crypto-icons/types";
// Custom dimensions
// With styling
// With custom fallback
ā} />
// Dynamic mode switching based on your app's theme state
const [isDark, setIsDark] = useState(false);
`
Installation
No installation required! Use with npx:
`bash
npx crypto-icon-next-cli@latest init
`
Quick Start
1. Initialize crypto icons in your Next.js project:
`bash
npx crypto-icon-next-cli@latest init
`
Supported for VITE projects as well!
`bash
npx crypto-icon-next-cli@latest init -f vite
`
2. Add some icons:
`bash
npx crypto-icon-next-cli@latest add --token BTC ETH
npx crypto-icon-next-cli@latest add --wallet MetaMask TrustWallet
npx crypto-icon-next-cli@latest add --system Ethereum Polygon
`
3. Use in your components:
`tsx
import { CryptoIcon } from "./components/crypto-icons";
export function WalletBalance() {
return (
{/ Icons that exist in the map will display the image /}
{/ Icons that don't exist will show fallback text /}
{/ Custom fallback /}
? } />
Universal Icon Component Benefits:
ā
One component for all icons - No need for separate IconBTC, IconETH, etc.
ā
Dynamic icon loading - Pass any icon name as a string
ā
Fallback support - Shows text or custom component when icon not found
ā
Type-safe - Full TypeScript support with intellisense
ā
No bundle bloat - Only loads the icons you actually use
Commands
$3
Configure default settings for the CLI:
`bash
npx crypto-icon-next-cli@latest config
Options:
-d, --dir Set default target directory
-i, --image-path Set default image base path
-r, --reset Reset configuration to defaults
Examples:
npx crypto-icon-next-cli@latest config
npx crypto-icon-next-cli@latest config --dir ./components/icons
npx crypto-icon-next-cli@latest config --image-path /assets/crypto
npx crypto-icon-next-cli@latest config --reset
`
$3
Initialize the crypto icons structure in your project:
`bash
npx crypto-icon-next-cli@latest init [options]
Options:
-d, --dir Target directory (default: from config or ./src/components/crypto-icons)
`
$3
Add crypto icon components:
`bash
npx crypto-icon-next-cli@latest add [options]
Options:
-t, --token Add token icons (e.g., BTC ETH SOL)
-w, --wallet Add wallet icons (e.g., MetaMask TrustWallet)
-s, --system Add system icons (e.g., Ethereum Polygon)
-d, --dir Target directory (default: from config or ./src/components/crypto-icons)
Examples:
npx crypto-icon-next-cli@latest add --token BTC ETH SOL
npx crypto-icon-next-cli@latest add --wallet MetaMask TrustWallet Coinbase
npx crypto-icon-next-cli@latest add --system Ethereum Polygon BSC
`
$3
Remove crypto icon components:
`bash
npx crypto-icon-next-cli@latest remove [options]
Options:
-t, --token Remove token icons
-w, --wallet Remove wallet icons
-s, --system Remove system icons
-d, --dir Target directory (default: from config or ./src/components/crypto-icons)
Examples:
npx crypto-icon-next-cli@latest remove --token BTC
npx crypto-icon-next-cli@latest remove --wallet MetaMask
`
Project Structure
After initialization, your project will have this structure:
`
src/components/crypto-icons/
āāā CryptoIcon.tsx # Universal icon component
āāā types/
ā āāā index.ts # Main type exports
ā āāā TokenSymbol.ts # Token symbols enum
ā āāā WalletName.ts # Wallet names enum
ā āāā SystemName.ts # System names enum
āāā constants/
ā āāā imagePaths.ts # Central icon map
āāā utils/
ā āāā theme.ts # Theme detection utilities
āāā index.ts # Main exports
`
Universal Component Architecture
Instead of generating individual component files for each icon, this CLI uses a universal component approach:
`tsx
// ā Old approach (individual components)
import { IconBTC, IconETH, IconMetaMask } from "./crypto-icons/tokens";
// ā
New approach (universal component)
import { CryptoIcon, TokenSymbol, WalletName } from "./crypto-icons";
function Portfolio() {
return (
);
}
`
Icon Sources
All icons are automatically loaded from Firebase Storage:
`typescript
// constants/imagePaths.ts
export const iconMap: Record = {
BTC: {
lightMode: baseImgUrlToken("BTC-lightmode"),
darkMode: baseImgUrlToken("BTC-darkmode"),
},
MetaMask: {
lightMode: baseImgUrlWallet("MetaMask-lightmode"),
darkMode: baseImgUrlWallet("MetaMask-darkmode"),
},
Ethereum: {
lightMode: baseImgUrlSystem("Ethereum-lightmode"),
darkMode: baseImgUrlSystem("Ethereum-darkmode"),
},
// ... more icons
};
`
$3
- Tokens: https://firebasestorage.googleapis.com/v0/b/crypto-images-token/o/[TOKEN_NAME]-[mode].png?alt=media
- Wallets: https://firebasestorage.googleapis.com/v0/b/crypto-images-wallet/o/[WALLET_NAME]-[mode].png?alt=media
- Systems: https://firebasestorage.googleapis.com/v0/b/crypto-images-system/o/[SYSTEM_NAME]-[mode].png?alt=media
Manual Theme Control
Icons support both light and dark variants. You control the display mode manually:
`tsx
// Light mode (default)
// Dark mode
// Dynamic mode based on your app's theme state
const [isDark, setIsDark] = useState(false);
// With next-themes or other theme libraries
import { useTheme } from "next-themes";
function MyComponent() {
const { theme } = useTheme();
return (
name="BTC"
size={32}
mode={theme === "dark" ? "dark" : "light"}
/>
);
}
`
Requirements
- Next.js 13+ (with app router support)
- TypeScript
- Tailwind CSS
- No local images required - Icons served from Firebase Storage
Troubleshooting
$3
If you're using Git Bash on Windows and encounter issues with image paths being converted to Windows paths (e.g., C:/Program Files/Git/assets/crypto), you can:
1. Use quotes around the path:
`bash
npx crypto-icon-next-cli@latest config --image-path "/images/crypto"
`
2. Manually edit the config file:
`bash
# Edit .crypto-icons.json directly
{
"defaultDirectory": "./src/components/icons",
"imageBasePath": "/images/crypto"
}
`
3. Use double slashes to escape:
`bash
npx crypto-icon-next-cli@latest config --image-path "//images/crypto"
`
$3
The CLI stores configuration in .crypto-icons.json in your project root. You can edit this file directly if needed:
`json
{
"defaultDirectory": "./src/components/crypto-icons",
"imageBasePath": "/images/crypto"
}
`
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License
Advanced Usage
$3
The CryptoIcon component supports comprehensive error handling and loading states:
`tsx
import { CryptoIcon } from "./components/crypto-icons";
export function AdvancedIconExample() {
const [loadingState, setLoadingState] = useState("");
return (
{/ Basic error handling /}
name="BTC"
size={48}
onError={(error) => console.error("Icon failed to load:", error)}
onLoadingComplete={(result) => console.log("Icon loaded:", result.naturalWidth, "x", result.naturalHeight)}
/>
{/ Custom loading component /}
} />
{/ Custom error component /}
name="INVALID_ICON"
size={48}
errorComponent={
ā
}
/>
{/ Blur placeholder /}
);
}
`
$3
Pass any Next.js Image props for advanced customization:
`tsx
import { CryptoIcon } from "./components/crypto-icons";
export function CustomizedIcon() {
return (
name="BTC"
size={64}
// Next.js Image props
priority={true}
quality={90}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
unoptimized={false}
loader={({ src, width, quality }) => {
return ${src}?w=${width}&q=${quality || 75};
}}
// Custom callbacks
onLoadingComplete={(result) => {
console.log("Image loaded successfully");
}}
onError={(error) => {
console.error("Failed to load image:", error);
}}
// Styling
className="rounded-full border-2 border-blue-500 shadow-lg hover:scale-110 transition-transform"
style={{ filter: "drop-shadow(0 4px 8px rgba(0,0,0,0.2))" }}
/>
);
}
`
$3
`tsx
import { CryptoIcon } from "./components/crypto-icons";
import { useTheme } from "next-themes";
export function ThemeAwareIcon() {
const { theme } = useTheme();
return (
name="SOL" // SOL is a special icon with different light/dark versions
mode={theme === "dark" ? "dark" : "light"}
size={48}
className="transition-all duration-300"
/>
);
}
`
$3
`tsx
import { CryptoIcon } from "./components/crypto-icons";
import { useState } from "react";
const tokens = ["BTC", "ETH", "SOL", "ADA", "DOT", "AVAX"];
export function IconGrid() {
const [loadedIcons, setLoadedIcons] = useState>(new Set());
const handleIconLoad = (iconName: string) => {
setLoadedIcons((prev) => new Set(prev).add(iconName));
};
return (
{tokens.map((token) => (
name={token}
size={48}
className="mx-auto"
loadingComponent={}
onLoadingComplete={() => handleIconLoad(token)}
fallback={
{token.slice(0, 3)}
}
/>
{token}
{loadedIcons.has(token) && ā}
))}
);
}
``