Icon System Design in UI: Building Consistent Components
A handful of icons is manageable. Three hundred icons across six products, maintained by four teams? That's a system problem. Here's how to build an icon system that stays consistent at scale.
What You'll Learn
- How to structure icon components for maximum reuse
- Design-token integration for sizing, colour, and spacing
- Automated pipelines from design tool to production code
Why a "System" and Not Just a "Set"?
An icon set is a folder of SVG files. An icon system is:
- Component-based — Each icon is a self-contained component with a defined API (props for size, colour, label).
- Token-driven — Sizing and colour are controlled by design tokens, not hard-coded values.
- Automated — New icons flow from Figma to npm package without manual export steps.
- Documented — A searchable catalogue with usage guidelines, not a zip file on a shared drive.
Component Architecture
The Icon Wrapper
Create a single wrapper component that handles sizing, colour, and accessibility:
function Icon({ name, size = 'md', color = 'currentColor', label, ...props }) {
const sizes = { sm: 16, md: 24, lg: 32, xl: 48 };
const px = sizes[size] || sizes.md;
const SvgIcon = icons[name]; // Dynamic import map
return (
<svg
width={px}
height={px}
viewBox="0 0 24 24"
fill={color}
role={label ? 'img' : undefined}
aria-label={label}
aria-hidden={label ? undefined : 'true'}
{...props}
>
<SvgIcon />
</svg>
);
}
Benefits
- Single source of truth for sizing logic and accessibility
- Swap internals without changing consumer code
- Type-safe
nameprop catches typos at compile time
Design Tokens for Icons
Integrate icon sizing with your existing token system:
| Token | Value | Usage |
|---|---|---|
icon.size.sm | 16 px | Dense tables, inline text |
icon.size.md | 24 px | Standard UI elements |
icon.size.lg | 32 px | Feature highlights, cards |
icon.size.xl | 48 px | Hero sections, empty states |
icon.color.default | currentColor | Inherits text colour |
icon.color.muted | --color-text-muted | Secondary/disabled state |
icon.color.brand | --color-brand-primary | Accent actions |
Automated Pipeline
Figma (design source)
→ Figma API export (CI job)
→ SVGO optimisation
→ Component generation (svgr, unplugin-icons)
→ npm publish @yourorg/icons
→ Consumed by all products
Key Decisions
- Figma frame naming convention — Use
icon/{category}/{name}(e.g.,icon/navigation/arrow-left). - Export trigger — Push to a "release" branch in your Figma file, or run on schedule.
- Versioning — Semver the icon package. Adding icons = minor bump. Changing existing icons = major bump.
Handling Icon Variants
Most systems need at least two variants: outline (default) and filled (active/selected).
<Icon name="heart" variant="outline" /> // Navigation
<Icon name="heart" variant="filled" /> // Selected state
Implement variants as separate SVG sources sharing the same bounding box—the wrapper component selects the correct source based on the variant prop.
Migration Strategy
If you're moving from a folder-of-SVGs approach:
- Audit — List every icon currently in use. The Icojoy icon browser can help identify standard glyphs.
- Map — Match existing icons to your new naming convention.
- Wrap — Create the wrapper component and token file.
- Replace — Swap inline
<svg>/<img>references to<Icon>component calls. - Prune — Delete orphaned SVGs that no component references.
Explore structured icon packs on Icojoy packs to bootstrap your system with consistent, production-grade assets. Check licensing for team usage terms.
FAQ
How many icons justify building a system? If you have more than 30 icons or more than one product consuming them, invest in a system. Below that, a well-organised folder is fine.
Should I use a mono-repo for the icon package? If your products are already in a mono-repo, yes. Otherwise, a standalone package repo with its own CI is cleaner.
How do I handle one-off icons that don't fit the system? Allow "local" icons per product, but review quarterly. If a local icon is used in two or more products, promote it to the shared system.
Can I use Icojoy icons inside my icon system? Absolutely. Download SVGs from the Icojoy library, run them through your SVGO config, and import them as components—just like custom icons.
What about icon search and discoverability? Build a Storybook or internal catalogue page. Tag icons with keywords (not just names) and include visual previews. The Icojoy collections page is a good model for how to organise discoverable icon sets.