Respected automatically
When a visitor turns on reduce motion in their system settings, every wm animation and swap transition switches off. Swaps still change icon, instantly.
for developers
500 icons × 20 styles with the same names, grid and props everywhere: React, Vue, Svelte, Angular, Solid, a web component, CSS classes and plain SVG. Tree-shakable, typed, currentColor by default, zero runtime dependencies. Want them to move? Add the optional animations package.
Pick your tool. The default import is the Line style; every other style is a subpath with the same export names.
npm i @withicons/reactimport { Home, Search } from '@withicons/react' // line (default)
import { Home as HomeSolid } from '@withicons/react/solid'
export function Toolbar() {
return (
<nav>
<Home />
<Search size={20} strokeWidth={1.5} className="text-slate-500" />
<HomeSolid size={32} color="#e11d48" title="Home" />
</nav>
)
}npm i @withicons/vue<script setup>
import { Home, Search } from '@withicons/vue'
import { Home as HomeSolid } from '@withicons/vue/solid'
</script>
<template>
<Home />
<Search :size="20" :stroke-width="1.5" class="text-slate-500" />
<HomeSolid :size="32" color="#e11d48" title="Home" />
</template>npm i @withicons/svelte<script>
import { Home, Search } from '@withicons/svelte'
import { Home as HomeSolid } from '@withicons/svelte/solid'
</script>
<Home />
<Search size={20} strokeWidth={1.5} class="text-slate-500" />
<HomeSolid size={32} color="#e11d48" title="Home" />npm i @withicons/angularimport { Component } from '@angular/core'
import { WithIconComponent, Home, Search } from '@withicons/angular'
import { Home as HomeSolid } from '@withicons/angular/solid'
@Component({
selector: 'app-toolbar',
imports: [WithIconComponent],
template: `
<with-icon [icon]="Home" />
<with-icon [icon]="Search" [size]="20" [strokeWidth]="1.5" />
<with-icon [icon]="HomeSolid" [size]="32" color="#e11d48" title="Home" />
`,
})
export class ToolbarComponent { Home = Home; Search = Search; HomeSolid = HomeSolid }npm i @withicons/solidimport { Home, Search } from '@withicons/solid'
import { Home as HomeSolid } from '@withicons/solid/solid'
export function Toolbar() {
return (
<nav>
<Home />
<Search size={20} strokeWidth={1.5} class="text-slate-500" />
<HomeSolid size={32} color="#e11d48" title="Home" />
</nav>
)
}<script type="module" src="https://cdn.jsdelivr.net/npm/@withicons/web/dist/cdn.js"></script>
<with-icon name="home"></with-icon>
<with-icon name="home" variant="solid" size="32" color="#e11d48" label="Home"></with-icon>Works in any framework, or none. The page downloads only the icons it shows: about 7 KB gzipped for the element, then one small file per icon (a line icon is about 150 bytes gzipped). Style the inner svg with with-icon::part(svg).
<script src="https://cdn.jsdelivr.net/npm/@withicons/classes/dist/with-loader.js" defer></script>
<i class="with with-home"></i>
<i class="with with-search with-2x"></i>
<i class="with with-heart with-solid"></i>The loader (about 6 KB gzipped) links just the CSS of the icons on the page, in any mix of styles. Each icon is a CSS mask over currentColor, sized 1em. Zero JavaScript instead? Link one stylesheet per style, with-line.css (all 500 line icons, about 26 KB gzipped).
<!-- one sprite per style, served from your own site -->
<svg width="24" height="24"><use href="sprite-line.svg#with-home"/></svg>
<!-- or a single file -->
<img src="https://cdn.jsdelivr.net/npm/@withicons/static/dist/svg/line/home.svg" width="24" height="24" alt="Home">An <img> can’t inherit currentColor and renders black. Use inline SVG or the sprite to recolour.
@withicons/react React 18+@withicons/vueVue 3@withicons/svelte Svelte 4 & 5@withicons/angular Angular 17+, standalone@withicons/solid SolidJS@withicons/web<with-icon> custom element@withicons/classes Icon classes: <i class="with with-home">@withicons/static SVG files & sprites, no JS@withicons/coreData, aliases, toSvg()@withicons/search The search engine behind this site@withicons/mcpMCP server for AI agentswithiconsCLI: npx withiconsEvery icon is exported twice, Home and HomeIcon, so it never clashes with your own names. Component names are the PascalCase of the icon name: arrow-up-right → ArrowUpRight. Deep imports work too: @withicons/.
The same props in every framework package (Angular uses the same names as inputs; the web component uses size, color, stroke-width, absolute-stroke-width, label).
| Prop | Type | Default | What it does |
|---|---|---|---|
size | number | string | 24 | Width and height. |
color | string | currentColor | Inherits the text colour by default. |
strokeWidth | number | string | 1.75 | Line, Duo, Blueprint and Sketch (styles with live strokes). |
absoluteStrokeWidth | boolean | false | Keep the stroke the same pixel width at any size. |
title | string | — | Adds <title> and role="img". Without it the icon is aria-hidden. |
className / | string | — | Added to the svg’s own classes. |
<Settings strokeWidth={1.75} />import { Icon } from '@withicons/react'
<Icon name="home" variant="solid" size={20} /> // aliases work: name="bin" → trashIcon references every icon in every style. It’s dropped from your bundle when unused; when you do use it, prefer named imports wherever the name is static.
Twenty styles. Universal styles (Line, Solid and Duo) are for interfaces at any size. Creative styles (Gloss, Engrave, Blueprint and Sketch) shine at 32 px and up: marketing pages, empty states, illustrations. Playful styles (Glass, Kawaii, Sticker, Pixel and Retro) come with their own colours: the outline still follows currentColor, and every extra colour is a CSS variable you can override. Studio styles (Luxe, Bauhaus and Skeuo) are art-directed, premium looks for heroes, app tiles and brand moments; their colours are role-named variables (--with-luxe-c1, --with-bauhaus-accent…), so one palette recolours every one of them. Storybook styles (Anime, Gothic, Pastel, Coquette and Plush) are small illustrations: anime cel shading, Gothic cathedral detail, soft pastels, coquette bows and plush felt toys, with role-named colour variables too (--with-anime-c1, --with-plush-accent…).
@withicons/react universal@withicons/react/solid universal@withicons/react/duo universal@withicons/react/gloss creative@withicons/react/engrave creative@withicons/react/blueprint creative@withicons/react/sketch creative@withicons/react/glass playful@withicons/react/kawaii playful@withicons/react/sticker playful@withicons/react/pixel playful@withicons/react/retro playful@withicons/react/luxe studio@withicons/react/bauhaus studio@withicons/react/skeuo studio@withicons/react/anime storybook@withicons/react/gothic storybook@withicons/react/pastel storybook@withicons/react/coquette storybook@withicons/react/plush storybook@withicons/motion Make any icon move: a bell that rings, a heart that beats, a play button that flips into pause.
Animations are a separate, optional add-on. Your icons never need it, and it works with every style and every package: put the classes on the element that holds the icon. Inline SVGs move part by part, so decorations and shadows never spin along with the object. Every icon comes with its own animation chosen to fit what it means, and you can pick from 32 presets and 12 swap transitions.
Not a developer? Open any icon, go to Customize › Motion and download an Animated SVG for your website or Notion, or a GIF for your slides. Free animated icons. Step-by-step guide.
npm i @withicons/motionAll presets in one stylesheet (27.7 KB gzipped), plus an optional script (35.7 KB gzipped) for scroll-triggered motion, swaps from code and the element.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@withicons/motion/dist/motion.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@withicons/motion/dist/icons/bell.css">motion.css has the presets (about 10 KB gzipped). icons/ adds one icon’s own motion (data-wm="bell"), a few hundred bytes each; icons.css has all 500 at once (about 18 KB gzipped). Pin a version in production.
No JavaScript needed. Wrap the icon (or put the classes on <with-icon> / <i>) and choose when it moves.
<!-- its own motion, forever -->
<span class="wm wm-loop" data-wm="bell"><svg …bell…></svg></span>
<!-- plays when the button is hovered or focused -->
<button class="wm-trigger">
<span class="wm wm-hover" data-wm="bell"><svg …></svg></span> Notifications
</button>
<!-- choose the preset, tune it with CSS variables -->
<span class="wm wm-loop wm-p-spin" style="--wm-dur: 2s"><svg …settings…></svg></span>
<i class="with with-star wm wm-hover wm-p-twinkle"></i>| Class | What it does |
|---|---|
wm | Base class on the element that holds the icon (a span, <with-icon> or <i>). |
wm-loop | Plays forever: calm, seamless motion. |
wm-hover | Plays once on hover, keyboard focus or tap of the icon, or of any ancestor with wm-trigger (like a button). |
wm-once | Plays once when the page loads. |
wm-inview | Plays once when it scrolls into view (needs motion.js). |
wm-paused | Holds still. Toggle it to pause and resume. |
data-wm="bell" | Uses that icon’s own motion from icons.css: the right pivot, direction and speed. |
wm-p-<preset> | Picks any preset yourself, e.g. wm-p-tada. Overrides the icon’s own. |
wm-parts | Set for you by motion() and <with-icon> when the SVG has part tags. Only needed by hand in browsers without :has(). |
wm-force | Keeps moving even when the visitor asked for reduced motion. Use only for essential feedback like a loader. |
| Variable | Changes | Example |
|---|---|---|
--wm-dur | seconds per cycle | --wm-dur: 2s |
--wm-k | intensity, 0.25 to 2 | --wm-k: 1.5 |
--wm-ox / | pivot point, in % of the icon | --wm-ox: 50%; --wm-oy: 15% |
--wm-dx / | direction for nudge, pass, rise… | --wm-dx: 0. |
--wm-steps | stepped motion (clock hands) | --wm-steps: 12 |
--wm-deco | how decorations move (none keeps them still) | --wm-deco: none |
Spinning a whole drawing makes its backdrop square, its sparkles and its shadow spin too, and the icon looks broken. So every style tags what it draws, and the motion moves the parts: a sun turns while its backdrop only breathes, a heart beats while its sparkles twinkle on their own, a rocket lifts while its shadow stays on the ground, and a bell’s clapper rings a beat behind the bell.
You don’t add anything. It happens whenever an inline SVG sits directly inside a wm wrapper, or in <with-icon>. Icons in <img> and <i class="with …"> tags, swaps and the draw preset still move as one piece.
bell · Line
The bell plays ring and its moving part plays ring a beat behind.
moon · Bauhaus
The moon plays breathe and its decorations twinkle on their own loop.
cloud · Luxe
The cloud plays float and its shadow stays on the ground and shrinks as it lifts.
heart · Sticker
The heart plays beat, its decorations drift gently on their own loop and its shadow moves with it.
moon · --wm-deco: none
The same icon with its decorations kept still: only the object moves.
| Tag on an SVG node | What it is | While the icon moves |
|---|---|---|
(no class), wm-k | the object itself | plays the move, about the icon’s pivot |
wm-a, wm-s | a moving part (clapper, lid, hand) and a badge | follows the object, or plays its own move from the spec’s parts, with a delay |
wm-deco | decoration: backdrop shapes, sparkles, hearts, stars, confetti, accent dots | its own gentle loop (breathe, float or twinkle) about its own centre, out of step with the object. It never spins along |
wm-shadow | cast shadow or ground | stays on the ground and shrinks or fades as the object lifts (float, bounce, rise, drop, jelly); otherwise moves with it |
wm-shine | highlight on the object | moves with the object |
<!-- the icon's own moves, part by part (needs icons.css) -->
<span class="wm wm-loop" data-wm="sun"><svg …sun, bauhaus…></svg></span>
<!-- keep the decorations still: only the object moves -->
<span class="wm wm-loop" data-wm="sun" style="--wm-deco: none"><svg …></svg></span>
<!-- or choose their loop: wm-deco-breathe | wm-deco-float | wm-deco-twinkle -->
<span class="wm wm-loop wm-p-spin" style="--wm-deco: wm-deco-float"><svg …></svg></span>import { motion } from '@withicons/motion'
motion(el, 'sun') // the sun turns, its backdrop breathes
motion(el, 'sun', { deco: 'still' }) // 'breathe' | 'float' | 'twinkle' | 'still'The tags are plain classes (class="wm-deco"): harmless without the motion CSS and kept by every package. A preset you pick (wm-p-spin) moves the object and its parts together, while decorations and shadows keep their own behaviour. Animated SVG, GIF, video and Lottie downloads move part by part too, and record until the decoration loop comes back round.
Each preset is one CSS animation that works on every icon. Click a card to copy its classes.
Presets marked as one-shots (pop, tada, shake…) are made for hover and taps; the rest loop seamlessly. draw traces the strokes of outline styles and falls back to pop on filled ones.
Stack two icons in a wm-swap wrapper. The second one shows when the wrapper (or a wm-trigger around it) is hovered, or when it has .is-on or aria-pressed="true": perfect for play/pause, show/hide password, menu/close and like buttons.
Click an icon to swap it.
<button aria-pressed="false" aria-label="Play">
<span class="wm-swap wm-fx-flip">
<svg class="wm-a" …play…></svg>
<svg class="wm-b" …pause…></svg>
</span>
</button>
<script>
button.onclick = () => button.setAttribute('aria-pressed', button.getAttribute('aria-pressed') !== 'true')
</script>Effects (add wm-fx- in front): fade, scale, rotate, flip, slide-up, slide-down, slide-left, slide-right, blur, spin, morph, draw. Draw needs an outline style and falls back to fade. Add wm-loop to a swap to alternate forever.
The classes are the whole API, so they work in any framework. Import the CSS once, then wrap icons.
import '@withicons/motion/motion.css'
import '@withicons/motion/icons.css' // each icon's own animation
import { useState } from 'react'
import { Bell, Play, Pause } from '@withicons/react'
export function Toolbar() {
const [playing, setPlaying] = useState(false)
return (
<>
{/* rings on hover or keyboard focus of the button */}
<button className="wm-trigger">
<span className="wm wm-hover" data-wm="bell"><Bell /></span> Notifications
</button>
{/* play turns into pause with a flip */}
<button aria-label={playing ? 'Pause' : 'Play'} onClick={() => setPlaying(p => !p)}>
<span className={'wm-swap wm-fx-flip' + (playing ? ' is-on' : '')}>
<Play className="wm-a" /><Pause className="wm-b" />
</span>
</button>
</>
)
}import { useEffect, useRef } from 'react'
import { motion } from '@withicons/motion'
// imperative: start / stop from code (e.g. while a request is pending)
export function useMotion(name, options) {
const ref = useRef(null)
useEffect(() => {
const m = motion(ref.current, name, options)
return () => m.destroy()
}, [name])
return ref // <span ref={useMotion('loader', { trigger: 'loop' })}><Loader /></span>
}<script setup>
import '@withicons/motion/motion.css'
import '@withicons/motion/icons.css'
import { ref } from 'vue'
import { Bell, Play, Pause } from '@withicons/vue'
const playing = ref(false)
</script>
<template>
<button class="wm-trigger">
<span class="wm wm-hover" data-wm="bell"><Bell /></span> Notifications
</button>
<button :aria-label="playing ? 'Pause' : 'Play'" @click="playing = !playing">
<span class="wm-swap wm-fx-flip" :class="{ 'is-on': playing }">
<Play class="wm-a" /><Pause class="wm-b" />
</span>
</button>
</template><script>
import '@withicons/motion/motion.css'
import '@withicons/motion/icons.css'
import { Bell, Play, Pause } from '@withicons/svelte'
let playing = false
</script>
<button class="wm-trigger">
<span class="wm wm-hover" data-wm="bell"><Bell /></span> Notifications
</button>
<button aria-label={playing ? 'Pause' : 'Play'} on:click={() => (playing = !playing)}>
<span class="wm-swap wm-fx-flip" class:is-on={playing}>
<Play class="wm-a" /><Pause class="wm-b" />
</span>
</button>// angular.json → "styles": ["node_modules/@withicons/motion/dist/motion.css",
// "node_modules/@withicons/motion/dist/icons.css", …]
import { Component, signal } from '@angular/core'
import { WithIconComponent, Bell, Play, Pause } from '@withicons/angular'
@Component({
selector: 'app-toolbar',
imports: [WithIconComponent],
template: `
<button class="wm-trigger">
<span class="wm wm-hover" data-wm="bell"><with-icon [icon]="Bell" /></span> Notifications
</button>
<button [attr.aria-label]="playing() ? 'Pause' : 'Play'" (click)="playing.set(!playing())">
<span class="wm-swap wm-fx-flip" [class.is-on]="playing()">
<with-icon class="wm-a" [icon]="Play" /><with-icon class="wm-b" [icon]="Pause" />
</span>
</button>
`,
})
export class ToolbarComponent { Bell = Bell; Play = Play; Pause = Pause; playing = signal(false) }<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@withicons/motion/dist/motion.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@withicons/web/dist/cdn.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@withicons/motion/dist/element.js"></script>
<with-icon name="bell" motion="loop"></with-icon> <!-- its own animation, forever -->
<with-icon name="heart" variant="solid" motion="hover"></with-icon> <!-- plays on hover / focus -->
<with-icon name="star" motion="once" preset="tada"></with-icon> <!-- once, when it appears -->
<with-icon name="play" swap-to="pause" swap-effect="flip" swap-trigger="click"></with-icon>Importing @withicons/ upgrades every <with-icon> on the page, now and later: motion (loop, hover, once, inview), preset, swap-to, swap-effect and swap-trigger (hover, click or loop). From a CDN it fetches only what the page animates: each icon’s own motion (icons/, a few hundred bytes) and its drawing, about 42 KB gzipped in all for one animated icon.
import { motion, swap, motionFor, PRESETS, EFFECTS } from '@withicons/motion'
motionFor('bell') // → { intent: 'rings like a notification just arrived', loop: {…}, hover: {…}, … }
const ring = motion(document.querySelector('#bell'), 'bell', { trigger: 'hover' })
ring.play(); ring.pause(); ring.destroy()
motion(el, 'loader', { trigger: 'loop', preset: 'tick', duration: 1 }) // override the preset
const toggle = swap(button, { from: playSvg, to: pauseSvg, effect: 'flip', trigger: 'click' })
toggle.toggle(true) // force "on"Each icon ships a small spec saying how it should move, in plain words and in numbers: its loop, its hover, how its parts move (parts.A for a moving part, parts.S for a badge, each with an optional delay), how its decorations move (deco), good alternatives and the icons it naturally turns into. motionFor(name) returns it.
{
"name": "bell",
"intent": "swings from its hook while the clapper rings a beat behind",
"loop": {
"preset": "ring",
"origin": [
12,
4.5
],
"amount": 0.6,
"duration": 2.4
},
"hover": {
"preset": "ring",
"origin": [
12,
4.5
],
"amount": 1.2,
"duration": 0.9
},
"parts": {
"A": {
"preset": "ring",
"origin": [
12,
4.5
],
"amount": 1.1,
"duration": 2.4,
"delay": 0.08
}
},
"deco": "twinkle",
"alt": [
{
"preset": "shake",
"amount": 0.6
},
{
"preset": "pop"
}
],
"swap": [
{
"to": "bell-off",
"effect": "flip"
},
{
"to": "bell-ring",
"effect": "fade"
},
{
"to": "bell@solid",
"effect": "scale"
}
]
}When a visitor turns on reduce motion in their system settings, every wm animation and swap transition switches off. Swaps still change icon, instantly.
Add wm-force for motion that carries meaning, like a loading spinner, and keep it calm.
One moving icon draws the eye; ten compete. Use loops for status (live, loading, recording) and hovers for everything else.
CSS animations are cheap (transform and opacity only), and the script pauses wm-inview icons that scroll away.
The Font Awesome way: plain tags, no build step. The loader fetches only the icons on the page, in any style:
<script src="https://cdn.jsdelivr.net/npm/@withicons/classes/dist/with-loader.js" defer></script>
<i class="with with-home"></i>
<i class="with with-home with-solid"></i>
<i class="with with-trash" role="img" aria-label="Delete"></i>No JavaScript at all? Link one stylesheet per style you use instead. Each holds every icon of that style: with-line.css is about 26 KB gzipped, the richest styles several hundred KB, and with-all.css (every style, about 6 MB gzipped) is for prototypes only.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@withicons/classes/dist/with-line.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@withicons/classes/dist/with-solid.css"> <!-- for with-solid -->With a bundler, install @withicons/ and import the same files:
npm i @withicons/classesimport '@withicons/classes/with-line.css' // every line icon
// or only what you use: the base rules, then one file per icon
import '@withicons/classes/with-base.css'
import '@withicons/classes/line/home.css'with-2xtwice the sizewith-spinrotate foreverwith-pulserotate in 8 stepswith-rotate-90quarter turnwith-flip-hmirror sidewayswith-flip-vmirror up-downwith-fwfixed width for listsAlso with-xs, with-sm, with-lg, with-3x to with-5x, with-rotate-180, with-rotate-270 and with-flip-both. Spin and pulse switch off for people who prefer reduced motion. For richer motion (a bell that rings, a play button that turns into pause) use @withicons/motion.
<script src="https://cdn.jsdelivr.net/npm/@withicons/classes/dist/with-icons.js" defer></script>
<i class="with with-home with-duo" style="--with-duo:#f59e0b"></i>
<i class="with with-settings" data-with-stroke-width="1.5"></i>The runtime swaps each tag for an inline SVG, downloads only the icons you show and understands aliases (with-bin → trash). Masks are single-colour; the runtime gives you the real duo tint and blueprint accent.
Every icon draws in currentColor, so it follows your text colour, hover states and dark mode for free. Two CSS variables add a second colour:
.toolbar { color: #111318; --with-duo: #7B5CFF; --with-accent: #00A3C4; }Every icon has one canonical kebab-case name plus dozens of aliases and synonyms. Names resolve in tiers, so a wrong guess never silently renders the wrong icon:
trash → trashArrowRight, arrow_right → arrow-rightbin → trashexpand → error listing the candidateshoem → error with the nearest namesimport { resolve, find } from '@withicons/core'
resolve('bin').name // 'trash'
resolve('expand') // throws WITH_AMBIGUOUS_ICON, err.candidates
resolve('hoem') // throws WITH_UNKNOWN_ICON, err.suggestions = ['home', …]
find('hoem') // nullWithout a title, icons render aria-hidden="true", so screen readers skip them. That’s right for icons next to text.
Pass title="Delete" (or label on <with-icon>) and the svg gets role="img" and a <title>.
For icon-only buttons, put aria-label on the <button> and keep the icon decorative.
with-spin, with-pulse and every @withicons/motion animation stop under prefers-reduced-motion.
<button aria-label="Delete file"><Trash /></button>
<Trash title="Delete" /> // standalone, meaningfulEach icon is its own ES module. Import Home and only Home ships: no registry, no runtime, no CSS. The packages have "sideEffects": false, so any modern bundler (Vite, webpack, Rollup, esbuild) drops the rest.
Not using npm? Everything works from a CDN or as files you copy into your project, and a page downloads only the icons it uses.
| What | URL / file |
|---|---|
| One SVG | https:// |
| Web component | https:// · about 7 KB gzipped, then each icon from its own small file |
| Icon classes | https:// (only the icons on the page) · zero JS: with-<style>.css, one style per file |
| Live icons | https:// · each live icon and style loads on first use |
| Sprites (download now) | line.svg · solid.svg · duo.svg · gloss.svg · engrave.svg · blueprint.svg · sketch.svg · glass.svg · kawaii.svg · sticker.svg · pixel.svg · retro.svg · luxe.svg · bauhaus.svg · skeuo.svg · anime.svg · gothic.svg · pastel.svg · coquette.svg · plush.svg |
| Class CSS (download now) | with-line.css · with-solid.css · with-duo.css · with-gloss.css · with-engrave.css · with-blueprint.css · with-sketch.css · with-glass.css · with-kawaii.css · with-sticker.css · with-pixel.css · with-retro.css · with-luxe.css · with-bauhaus.css · with-skeuo.css · with-anime.css · with-gothic.css · with-pastel.css · with-coquette.css · with-plush.css |
| Animations | https:// + each icon’s own motion, dist/ (the element links these for you; icons.css has all of them) · download motion.css · motion.js |
| Metadata | icons.json · names, categories, aliases, tags |
Pin a version in production (@withicons/): versioned files are cached for good, by the CDN and the browser. Any single icon can also be copied or downloaded as SVG or PNG from the library.
Every icon page exports 36 formats in the browser, in the chosen style, colours, size and motion. Nothing is uploaded: the converters are plain scripts in site/js/export/. 29 of them also come out of withicons export, so design teams, app builds and CI get the same files without a browser. For a plain-language comparison, see which file should I use?
npx withicons export home settings --format svg,pdf,png --out icons
npx withicons export star --style sticker --format favicon-pack --background "#ffffff" --out public
npx withicons export bell --format lottie --motion hover
npx withicons export bell --format gif --background "#ffffff" --out slides
npx withicons export rocket --style luxe --format pptx-animated --background "#0f172a"
npx withicons export heart --style retro --palette classic-red --format android,ios --out app/icons
npx withicons export heart --all-styles --format png --size 256 --out hearts
npx withicons export trash --format jsx --out - > src/icons/Trash.jsx| Format | File | Transparent | CLI | What it is |
|---|---|---|---|---|
png | .png | Yes | Yes | The safe choice for slides, docs, chat and design tools: sharp at any size you pick, with a see-through background. |
webp | .webp | Yes | Browser only | For websites: like PNG with a see-through background, but a smaller file that loads faster. |
jpg | .jpg | No | Browser only | For places that refuse PNG (some forms, email tools, older software). No transparency: sits on a solid colour, white unless you pick one. |
avif | .avif | Yes | Browser only | The smallest modern web image with a see-through background. Only offered where your browser can create it. |
png-set | .zip | Yes | Yes | For apps and retina screens: one ZIP with the icon at 1x, 2x, 3x and 4x plus a README on which file goes where (iOS, Android, web, slides). |
svg-flat | .svg | Yes | Yes | Sharp at any size with your colours locked in. Drop it into Figma, Illustrator, Canva, Keynote or Google Slides. |
svg | .svg | Yes | Yes | For developers: keeps currentColor and the --with-* CSS variables (your colours as defaults), so CSS can recolour it. |
pdf | .pdf | Yes | Yes | A true vector PDF that prints razor sharp. Opens in Illustrator, Keynote, Word, PowerPoint and any PDF viewer. |
eps | .eps | No | Yes | Vector EPS for older design and print tools that ask for it. EPS has no transparency: see-through parts are blended onto your background (or white). |
gif | .gif | Yes, hard edges | Yes | Plays everywhere: Slack, email, Notion, Google Slides, PowerPoint. Edges are blended with a matte colour (white, or your background), so pick the colour it will sit on. |
apng | .png | Yes | Yes | An animated PNG with smooth, truly see-through edges on any background. Plays in every modern browser; elsewhere it shows the still icon. |
webp-animated | .webp | Yes | Browser only | An animated image for websites and apps: smooth see-through edges and lossless by default, often smaller than GIF. Only offered where your browser can create WebP. |
webm | .webm | Yes in Chrome and Edge | Browser only | A tiny looping video for websites and video editors. Keeps the see-through background in Chrome and Edge (VP9 alpha); other browsers record it on your background colour. |
mp4 | .mp4 | No | Browser only | A short video for Keynote, PowerPoint, social posts and video editors. No transparency: it plays on your background colour (white unless you pick one). |
png-sequence | .zip | Yes | Browser only | Every frame as a numbered, see-through PNG: import as an image sequence in After Effects, Premiere, DaVinci Resolve, Blender or a game engine. |
animated-svg | .svg | Yes | Yes | One small, sharp-at-any-size file that animates by itself: in an <img>, opened in a browser, or pasted into a page. Uses the same motion as the site (CSS keyframes inside). |
lottie | .json | Yes | Yes | Vector animation for apps and sites (lottie-web, iOS, Android, Flutter, React Native) and for motion designers in After Effects or LottieFiles. Stays sharp at any size. |
dotlottie | .lottie | Yes | Yes | The compact Lottie package (.lottie) with playback settings built in. Drop it into LottieFiles, Webflow, Framer or the dotLottie players. |
pptx | .pptx | Yes | Yes | A ready 16:9 slide with the icon centred. Stays sharp and recolourable in PowerPoint 365; opens in Keynote and Google Slides too. |
pptx-sheet | .pptx | Yes | Yes | A deck showing this icon in every style side by side, then one slide per style. Handy for picking a look with your team. |
pptx-animated | .pptx | Yes, hard edges | Yes | A ready 16:9 slide with the icon moving: an animated GIF that plays in PowerPoint, Keynote and Google Slides. Pick your slide colour as the background so the edges blend in. |
docx | .docx | Yes | Yes | A Word document with the icon placed inline, ready to copy into reports, briefs and handouts. Vector in Word 365, picture elsewhere. |
ico | .ico | Yes | Yes | Windows and browser icon file with 16, 32, 48, 64 and 256 px inside. Use it as favicon.ico or a desktop shortcut icon. |
favicon-pack | .zip | Yes | Yes | Everything a website needs: favicon.ico, favicon.svg, Apple touch icon, Android/PWA icons, site.webmanifest and the <link> tags to paste. |
android | .xml | Yes | Yes | Vector drawable XML for Android Studio: drop it into res/drawable. Sharp on every screen density, no PNGs needed. |
ios | .zip | Yes | Yes | Drag the .imageset folder into Assets.xcassets in Xcode: a vector PDF that stays sharp on every iPhone and iPad. One-colour icons tint like SF Symbols. |
jsx | .jsx | — | Yes | A ready-to-use React component file with size, color and title props. Motion included when you added one. |
tsx | .tsx | — | Yes | The React component with TypeScript types, for typed React and Next.js projects. |
vue | .vue | — | Yes | A Vue 3 single-file component (<script setup>) with size, color and title props. |
svelte | .svelte | — | Yes | A Svelte component (works in Svelte 4 and 5) with size, color and title props. |
react-native | .jsx | — | Yes | A react-native-svg component for iOS and Android apps. Colours are baked in (React Native has no CSS variables). |
angular | .ts | — | Yes | An Angular standalone component (Angular 17+) with size, color and title inputs. |
html | .html | — | Yes | An inline SVG snippet to paste into any web page; recolour it with CSS. Includes the motion classes when you added one. |
css | .css | — | Yes | A CSS class that shows the icon as a background image, plus a -mask class that takes the text colour. |
data-uri | .txt | — | Yes | The icon as one line of text (data:image/svg+xml,...) for CSS url(), <img src> or email templates. |
base64 | .txt | — | Yes | The icon as a base64 data URI (data:image/svg+xml;base64,...) for tools and APIs that only accept base64. |
CLI options: --format (comma separated, or all), --style or --all-styles, --size, --background transparent|#hex, --padding 0–0.4, colours as for get (--palette, --color, --c1 … --edge), --motion loop|hover|once|swap|none|<preset> for the animated and code formats (with --to, --effect, --fps, --seconds, --loop, --matte), --out <folder> (- prints one file) and --json. Animated GIF, APNG and the animated PowerPoint slide are rendered frame by frame from the same keyframes as this site, no browser needed: give a GIF the colour of the slide it sits on (--background, or --matte to keep it transparent). PNG-based and animated formats use @resvg/resvg-js, an optional dependency; WebP, JPG, AVIF, animated WebP and video are made in the browser only.
Search the set, print code and get import lines without leaving your terminal. It works offline: everything ships in the package (withicons, unscoped).
npx withicons search "throw away"
npx withicons get home --style solid --format react
npx withicons add home settings delete --framework react
# import { Home, Settings, Trash } from '@withicons/react'
npx withicons get trash --size 32 > trash.svg
npx withicons export home --format svg,pdf,png --out icons| Command | What it does |
|---|---|
search <words…> | Ranked icons, typo-tolerant (settigns), synonyms (bin), phrases (recycle bin), plain language (money). |
get <name…> | Code for one or more icons; names or aliases (delete → trash). |
export <name…> | Save files: SVG, PDF, EPS, PNG, ICO, favicon pack, Android, iOS, components, PowerPoint, Word, Lottie. All export formats. |
add <name…> | Import line + usage for --framework react (default), vue, svelte, angular, solid, web-component, html-class, svg. |
resolve <name> | Does a name or alias map to exactly one icon? |
styles · categories [category] | The catalogue. |
mcp | Runs the MCP server over stdio (same as npx -y @withicons/). |
Options: --style/-s, --format/-f (svg, react, vue, svelte, angular, solid, html-class, web-component, data-uri), --framework/--fw, --size, --color, --limit/-n, --category/-c, and --json for scripts and AI agents (exit code 0 = found, 1 = not found or ambiguous, 2 = usage error).
Building with an AI assistant? The MCP server, HTTP API and agent skill give it the same search and the real code.
skip the docs
One click copies a brief that points Claude, ChatGPT, Gemini, Perplexity or Grok at our agent skill and llms.txt, then opens it. Describe your stack and the UI you’re building, and it answers with the best-fit icons (real names only), the right style and paste-ready code. On any icon page, the same buttons can code that icon for your stack or build a matching set around it. For coding agents, connect the MCP server instead.
with icons is MIT licensed and developed in the open. The repository opens at launch.
github.com/