Skip to main content

Icon System Design in UI: Building Consistent Components

· 4 min read

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 name prop catches typos at compile time

Design Tokens for Icons

Integrate icon sizing with your existing token system:

TokenValueUsage
icon.size.sm16 pxDense tables, inline text
icon.size.md24 pxStandard UI elements
icon.size.lg32 pxFeature highlights, cards
icon.size.xl48 pxHero sections, empty states
icon.color.defaultcurrentColorInherits text colour
icon.color.muted--color-text-mutedSecondary/disabled state
icon.color.brand--color-brand-primaryAccent 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

  1. Figma frame naming convention — Use icon/{category}/{name} (e.g., icon/navigation/arrow-left).
  2. Export trigger — Push to a "release" branch in your Figma file, or run on schedule.
  3. 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:

  1. Audit — List every icon currently in use. The Icojoy icon browser can help identify standard glyphs.
  2. Map — Match existing icons to your new naming convention.
  3. Wrap — Create the wrapper component and token file.
  4. Replace — Swap inline <svg> / <img> references to <Icon> component calls.
  5. 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.