@steellgold/mkicon
v0.6.0
Published
Transform SVG icons into beautiful React, Vue, or Svelte components with zero config
Downloads
1,095
Maintainers
Readme
🎨 mkicon
Transform SVG icons into beautiful React, React Native, Vue, or Svelte components with zero config.
✨ Features
- 🚀 Zero Config - Get started instantly with
mkicon init - 📚 Icon Libraries - Browse and import from Lucide Icons (1700+ icons)
- 🎨 Multi-Framework - Support for React, React Native, Vue 3, and Svelte
- 📦 Batch Processing - Convert multiple SVG files at once
- 🔧 Fully Customizable - Control props, naming, and file formats
- ⚡ Auto-Optimization - Built-in SVGO integration
- 🎯 Smart Formatting - Auto-adapts to Prettier, Biome, ESLint, or EditorConfig
- 📝 Auto-Index - Maintains index.ts for easy imports
- 🌐 URL Support - Fetch icons directly from URLs
- 🔍 Smart Suggestions - Auto-detect icon names from URLs
- 💾 Persistent Config - Set it once, use it forever
📦 Installation
# Install globally (recommended)
npm install -g @steellgold/mkicon
pnpm add -g @steellgold/mkicon
# Then use the short command
mkicon🚀 Quick Start
Option 1: Instant Setup (Recommended)
Initialize with best practice defaults:
cd my-project
mkicon initThis creates .mkicon.json with:
- Framework: React (TypeScript)
- Folder:
src/components/icons/ - Optimization: Enabled
- Props: size, color, className
- Auto-index: Enabled
Customize later with mkicon config if needed.
Option 2: Interactive Setup
Run mkicon and follow the prompts:
mkiconConfigure:
- Where to create icons
- Framework (React, React Native, Vue, or Svelte)
- Optimization preferences
- Props configuration
- Naming conventions
A .mkicon.json file will be created - commit it to your repo!
Create Your First Icon
After setup, paste your SVG when prompted:
mkicon
# Paste SVG, enter icon name, done! ✨📖 Usage
Interactive Mode (Default)
mkiconPrompts you through:
- How to provide SVG (paste/URL/file)
- Icon name
- Creates component automatically
Semi-Interactive Mode (Fast! ⚡)
Skip the source selection and jump straight to input:
# Paste mode - prompts for SVG and name
mkicon paste
# URL mode - prompts for URL and name
mkicon url
# File mode - prompts for file path and name
mkicon fileThis is the fastest way to create icons - no source selection needed!
CLI Mode (Non-Interactive)
Provide all arguments for fully automated icon creation:
# From SVG code
mkicon -n UserPlus -p '<svg>...</svg>'
# From URL
mkicon -n Arrow -u https://example.com/icon.svg
# From file
mkicon -n Home -f ./icons/home.svg
# Legacy syntax (still supported)
mkicon --name UserPlus --svg '<svg>...</svg>'Batch Mode
Convert multiple SVG files at once:
mkicon batch ./svg-iconsThis will:
- Scan the folder for all
.svgfiles - Show a preview of found files
- Ask for confirmation
- Generate all components
- Update index.ts
- Track components in
.mkicon.lock.json(auto-added to.gitignore)
Tracking & Diff
mkicon tracks generated components in .mkicon.lock.json (automatically gitignored). This enables:
Diff — detect component drift
mkicon diffDetects when a component file has been manually edited or is out of sync with its SVG source. For each changed component, shows a line-by-line diff of the .tsx/.vue/.svelte file and lets you:
- Skip — leave it for now
- Show full diff — see the complete file diff
- Revert — restore the file to what mkicon would generate
Preview — visualise a component in the terminal
# Interactive fuzzy search
mkicon preview
# Jump directly to a component
mkicon preview BananaIcon
mkicon preview banana # fuzzy matchRenders the icon inline in the terminal with a side-by-side info panel (component name, source, viewBox, elements, generation date).
Export back to SVG
mkicon svg src/components/icons/BananaIcon.tsx
# Custom output path
mkicon svg src/components/icons/BananaIcon.tsx -o exports/banana.svgConverts a generated component back to a plain .svg file. Uses the original SVG from the lock file when available, otherwise extracts it from the component file.
Rebuild lock file
# After a fresh clone (lock file is gitignored)
mkicon batch --refresh
# shorthand:
mkicon batch -rRebuilds .mkicon.lock.json from existing component files without regenerating anything. Automatically matches components to their SVG source files. Also runs automatically when mkicon diff or mkicon preview detects a missing lock file.
Icon Library Browser
Browse and import icons from Lucide Icons (1700+ icons):
mkicon library
# or shorthand:
mkicon browseThis will:
- Open an interactive browser
- Search through 1700+ Lucide icons
- Preview icon details
- Import selected icons directly into your project
Multi-Variant Icons
Create icons with multiple variations controlled by props:
Directional Icons
Create a single component with direction variants:
mkicon --name Arrow --directiveThis will:
- Prompt you to select directions (up, down, left, right, etc.)
- Ask for SVG content for each direction
- Generate a single component with a
directionprop
Usage:
<ArrowIcon direction="up" />
<ArrowIcon direction="down" />
<ArrowIcon direction="left" />
<ArrowIcon direction="right" />Supported directions:
- Basic:
up,down,left,right - Diagonal:
up-right,up-left,down-right,down-left - Circle:
up-circle,down-circle,left-circle,right-circle - Special:
up-tray,down-tray,up-on-square,down-on-square - Combined:
up-down,left-right
Style Variants
Create a single component with style variants:
mkicon --name User --variantThis will:
- Prompt you to select styles (outline, solid, filled, etc.)
- Ask for SVG content for each style
- Generate a single component with variant props
Usage:
<UserIcon filled />
<UserIcon variant="outline" />
<UserIcon variant="solid" />Supported styles:
- Basic:
outline,solid,filled - Sizes:
mini,micro - Weights:
thin,light,regular,bold - Special:
duotone,sharp
Combined Variants
Combine both directional and style variants:
mkicon --name Arrow --directive --variantUsage:
<ArrowIcon direction="up" variant="solid" />
<ArrowIcon direction="down" filled />Automatic Detection in Batch Mode
When using batch mode, mkicon will automatically detect variant groups:
mkicon batch ./icons
# Detects: ArrowUp.svg, ArrowDown.svg, ArrowLeft.svg
# → Suggests creating a multi-variant <Arrow direction="..." /> componentThe detector looks for consistent naming patterns:
ArrowUp.svg,ArrowDown.svg→ Directional variantsUserOutline.svg,UserSolid.svg→ Style variants
You'll be prompted to confirm if you want to process them as multi-variant components.
Spinner Generator
Create animated loading spinner components:
mkicon spinner
# or shorthand:
mkicon spinThis will:
- Ask for spinner name
- Select framework (React, Vue, Svelte, React Native)
- Select animation type (CSS, Framer Motion, Motion One, Vue Transitions, Svelte Transitions, Reanimated)
- Generate spinner component with animation
React Example
import { motion } from "framer-motion";
export const SpinnerIcon = ({ size = 24, color = "currentColor" }) => {
return (
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
>
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color}>
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
</svg>
</motion.div>
);
};Vue Example
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
:width="size"
:height="size"
viewBox="0 0 24 24"
fill="none"
:stroke="color"
:class="['spinner', { 'animate-spin': animate }]"
>
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
</svg>
</template>
<script setup lang="ts">
withDefaults(
defineProps<{
size?: number | string;
color?: string;
animate?: boolean;
}>(),
{
size: 24,
color: "currentColor",
animate: true,
}
);
</script>Svelte Example
<script lang="ts">
import { fade } from "svelte/transition";
export let size: number | string = 24;
export let color: string = "currentColor";
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
width="{size}"
height="{size}"
viewBox="0 0 24 24"
fill="none"
stroke="{color}"
class="animate-spin"
>
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
</svg>React Native Example
import Animated, {
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
export const SpinnerIcon = ({ size = 24, color = "currentColor" }) => {
const rotation = useSharedValue(0);
rotation.value = withRepeat(withTiming(360, { duration: 1000 }), -1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ rotate: `${rotation.value}deg` }],
}));
return (
<Animated.View style={animatedStyle}>
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
<Path d="M21 12a9 9 0 1 1-6.219-8.56" stroke={color} />
</Svg>
</Animated.View>
);
};Requires
react-native-reanimatedinstalled for Reanimated animations.
Configuration Management
# Interactive config menu
mkicon config
# Show current config
mkicon config --show
# Inspect detected project formatting
mkicon inspect-config⚙️ Configuration
The .mkicon.json file in your project root:
{
"$schema": "https://unpkg.com/@steellgold/mkicon/schema.json",
"version": "1.0.0",
"baseDir": "src/components",
"iconsFolder": "icons",
"framework": "react",
"typescript": true,
"optimize": true,
"maintainIndex": true,
"props": {
"size": true,
"color": true,
"className": true,
"style": false
},
"naming": {
"suffix": "Icon",
"suffixEnabled": true,
"componentCase": "PascalCase",
"fileCase": "PascalCase"
}
}Configuration Options
| Option | Type | Default | Description |
| ---------------------- | ------------------------------------------------ | -------------- | ------------------------------ |
| baseDir | string | - | Base directory for icons |
| iconsFolder | string | "icons" | Subfolder name |
| framework | "react" \| "react-native" \| "vue" \| "svelte" | "react" | Target framework |
| typescript | boolean | true | Generate TypeScript files |
| optimize | boolean | true | Optimize SVG with SVGO |
| maintainIndex | boolean | true | Auto-maintain index.ts |
| props.size | boolean | true | Enable size prop |
| props.color | boolean | true | Enable color prop |
| props.className | boolean | true | Enable className prop |
| props.strokeWidth | boolean | false | Enable strokeWidth prop |
| props.style | boolean | false | Enable style prop |
| naming.suffix | string | "Icon" | Component name suffix |
| naming.suffixEnabled | boolean | true | Add suffix to names |
| naming.componentCase | "PascalCase" \| "camelCase" | "PascalCase" | Component name format |
| naming.fileCase | "PascalCase" \| "kebab-case" \| "camelCase" | "PascalCase" | File name format |
| adaptToProject | boolean | true | Auto-detect project formatting |
Automatic Project Formatting Adaptation
mkicon automatically adapts to your project's formatting rules by detecting and applying configurations from:
Priority order:
- Prettier - Most explicit formatter configuration
- Biome - Modern formatter + linter combo
- ESLint - Formatting rules extraction
- EditorConfig - Basic indentation and line endings
- mkicon defaults - Fallback if no config found
Detected settings:
- Quote style (single/double)
- Indentation (spaces/tabs, size)
- Semicolons (required/optional)
- Trailing commas (none/es5/all)
- Bracket spacing
- Arrow function parentheses
- Line endings (LF/CRLF)
Example:
If your project uses Prettier with:
{
"semi": false,
"singleQuote": true,
"trailingComma": "all"
}mkicon will automatically generate components matching this style:
// Generated with your project's style
export const UserIcon = ({ size = 24, color = "currentColor" }) => {
return <svg>...</svg>;
};Disable adaptation:
# One-time disable
mkicon --no-adapt
# Permanent disable in .mkicon.json
{
"adaptToProject": false
}Inspect detected configuration:
mkicon inspect-configThis shows exactly what formatting rules mkicon detected from your project.
🎨 Generated Components
React Example
import type { SVGProps } from "react";
export interface UserPlusIconProps extends SVGProps<SVGSVGElement> {
size?: number | string;
color?: string;
}
export const UserPlusIcon = ({
size = 24,
color = "currentColor",
className,
...props
}: UserPlusIconProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
className={className}
{...props}
>
{/* SVG paths */}
</svg>
);
};React Native Example
import type { SvgProps } from "react-native-svg";
import { Svg, Path } from "react-native-svg";
export interface UserPlusIconProps extends SvgProps {
size?: number | string;
color?: string;
}
export const UserPlusIcon = ({
size = 24,
color = "currentColor",
...props
}: UserPlusIconProps) => {
return (
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} {...props}>
{/* SVG paths */}
</Svg>
);
};Requires
react-native-svginstalled in your project.
Vue Example
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
:width="size"
:height="size"
viewBox="0 0 24 24"
fill="none"
:stroke="color"
v-bind="$attrs"
>
<!-- SVG paths -->
</svg>
</template>
<script setup lang="ts">
withDefaults(
defineProps<{
size?: number | string;
color?: string;
}>(),
{
size: 24,
color: "currentColor",
}
);
</script>Svelte Example
<script lang="ts">
export let size: number | string = 24;
export let color: string = "currentColor";
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
width="{size}"
height="{size}"
viewBox="0 0 24 24"
fill="none"
stroke="{color}"
{...$$restProps}
>
<!-- SVG paths -->
</svg>📚 Examples
Using with Heroicons
mkicon \
--name ChevronRight \
--url https://raw.githubusercontent.com/tailwindlabs/heroicons/master/optimized/24/outline/chevron-right.svgUsing with Lucide
mkicon \
--name User \
--url https://lucide.dev/api/icons/userCustom SVG
mkicon --name Logo --svg '
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" fill="blue"/>
</svg>
'Batch from Figma Export
# Export icons from Figma to ./figma-icons/
mkicon batch ./figma-icons🔧 Auto-Generated Index
mkicon automatically maintains an index.ts file:
// Auto-generated by mkicon
// Do not edit manually - this file is updated automatically
export { ArrowIcon } from "./ArrowIcon";
export { HomeIcon } from "./HomeIcon";
export { UserIcon } from "./UserIcon";
export { UserPlusIcon } from "./UserPlusIcon";This allows clean imports:
// Instead of:
import { UserPlusIcon } from "@/components/icons/UserPlusIcon";
import { ArrowIcon } from "@/components/icons/ArrowIcon";
// You can do:
import { UserPlusIcon, ArrowIcon } from "@/components/icons";💡 Tips
File Naming
Choose the file naming format that fits your project:
- PascalCase -
UserPlusIcon.tsx(default) - kebab-case -
user-plus-icon.tsx - camelCase -
userPlusIcon.tsx
Preserve Existing PascalCase
mkicon is smart about naming:
# Input: "ClosedCaption" → ClosedCaptionIcon (preserves casing)
# Input: "closed-caption" → ClosedCaptionIcon (converts to PascalCase)
# Input: "userPlus" → UserPlusIcon (converts to PascalCase)Disable Icon Suffix
Don't want the "Icon" suffix?
mkicon config
# → Select "Naming configuration"
# → Disable suffixNow UserPlus becomes just UserPlus.tsx instead of UserPlusIcon.tsx.
🚀 Roadmap & TODO
📚 Additional Icon Libraries
Expand beyond Lucide Icons:
- Font Awesome
- Material Design Icons
- Feather Icons
- Bootstrap Icons
- Tabler Icons
- Iconoir
- Phosphor Icons
🔧 Framework Support
Additional framework targets:
- Angular (standalone components)
- Solid.js
- Qwik
- Preact
♿ Accessibility
Automatic accessibility improvements:
Auto aria-label - Generate from icon name
role="img" - Automatic role attribute
title & desc - Support for
<title>and<desc>SVG elementsAccessible by default - Best practices built-in
<UserIcon aria-label="User profile" role="img"> <title>User profile icon</title> <desc>An icon representing a user profile</desc> </UserIcon>
Want to contribute? Check out these TODOs or suggest new features in Issues!
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT © Gaëtan H
🔗 Links
Made with ❤️ by Gaëtan H
