Brik Design System
Components

Icons

Iconify + Phosphor icon reference. Inline SVGs via @iconify/react, no CDN calls.

BDS uses Phosphor icons via @iconify/react. Icons render as inline SVGs — no CDN, no flash-of-unstyled-icon, no bundle bloat from importing all icons.

Setup

PackagePurpose
@iconify/reactRenders any Iconify icon as a React <Icon> component
@iconify-json/phPhosphor icon data (bundled for offline / SSR)

BDS registers the Phosphor collection at startup in .storybook/preview.tsx via addCollection(). No CDN calls needed.

Use it for

  • Inline icons in buttons, badges, tooltips, fields
  • Decorative icons in cards and headers
  • Status / state markers paired with text
  • Anywhere a small (≤ 32px) glyph carries meaning

For larger illustrations and brand marks, use a static SVG asset directly. For non-icon visual primitives (ServiceTag, avatar fallbacks), use the dedicated component.

Import

import { Icon } from '@iconify/react';

For BDS-internal usage, prefer the named constants in components/icons.ts:

import { Star } from '@brikdesigns/bds/icons';

<Icon icon={Star} />

Usage

Direct string reference

The icon prop accepts a collection:name string. Phosphor icons use the ph: prefix.

<Icon icon="ph:star-fill" />
<Icon icon="ph:check" />
<Icon icon="ph:x-circle" />

Find available icons at phosphoricons.com.

BDS icon constants

For commonly-used icons in BDS components, prefer the named constants — protects against typos and centralizes the icon vocabulary.

import { Star, Check, XCircle } from '@brikdesigns/bds/icons';

<Icon icon={Star} />
<Icon icon={Check} />
<Icon icon={XCircle} />

Constants follow the pattern export const Name = 'ph:icon-name'.

Sizing

Iconify icons inherit font-size from their parent or accept explicit width / height props.

{/* Inherits parent font-size — recommended */}
<span style={{ fontSize: 24 }}>
  <Icon icon="ph:star-fill" />
</span>

{/* Explicit size */}
<Icon icon="ph:star-fill" width={24} height={24} />

For inline icons inside text, use 1em sizing so the icon scales with the surrounding text:

<button>
  <Icon icon="ph:plus" style={{ fontSize: '1em' }} />
  Add item
</button>

Phosphor weights

Phosphor provides six weights per icon. BDS primarily uses the regular and fill variants.

WeightSuffixUse
Regularph:nameDefault. Most contexts.
Boldph:name-boldEmphasis, IconButton labels at sm size
Fillph:name-fillActive/selected states, status badges
Lightph:name-lightDecorative or quiet contexts
Thinph:name-thinRare; very specific design intent
Duotoneph:name-duotoneEmpty states, illustrations
<Icon icon="ph:star" />          {/* outline, default weight */}
<Icon icon="ph:star-fill" />     {/* solid */}
<Icon icon="ph:star-bold" />     {/* heavier outline */}

Color / theming

Iconify icons render with fill="currentColor", so they inherit color from the CSS color of any ancestor — no per-icon fill prop needed. To recolor an icon, set color on it or a parent, ideally to a BDS text token rather than a raw hex:

{/* inherits the surrounding text color */}
<span style={{ color: 'var(--text-muted)' }}>
  <Icon icon="ph:info" /> Quiet hint
</span>

{/* status icon */}
<Icon icon="ph:check-circle-fill" style={{ color: 'var(--text-positive)' }} />

Text tokens commonly used for icon fill:

TokenUse
--text-primaryDefault icon next to body text
--text-secondary / --text-mutedQuiet / secondary icons
--text-linkIcons inside links
--text-positive / --text-negative / --text-infoStatus icons
--text-inverseIcons on dark / inverted surfaces

BDS text tokens are mode-aware, so an icon colored with one retones automatically in brik-dark — prefer them over hardcoded colors.

Service-line glyphs (ServiceTag)

ServiceTag's per-service glyphs are not Phosphor icons — they're custom SVG assets under components/ui/ServiceTag/icons/. They render via CSS mask-image with background-color: currentColor (not <img src>), so the fill is CSS-recolorable and inherits the tag's service text token:

.bds-service-tag--marketing { color: var(--text-service-marketing-on-light); }
.bds-service-tag__icon      { background-color: currentColor; /* masked glyph */ }

Each service line carries a mode-aware --text-service-{line}-on-light / -on-dark pair (brand, marketing, information, product, back-office), so the glyph retones per theme. Reach for ServiceTag rather than a raw <img> whenever you need a service-line glyph — Phosphor does not cover every icon need.

Adding icons to BDS

  1. Find the icon name at phosphoricons.com — copy the kebab-case name.
  2. Add a named constant to components/icons.ts using the ph:icon-name format.
  3. (Optional) Add the icon to a category in the Storybook stories so other contributors can find it.
// components/icons.ts
export const Heart = 'ph:heart';
export const HeartFill = 'ph:heart-fill';

When not to use

Don't use raw SVG inline. Iconify provides 200,000+ icons across multiple collections — you almost never need a one-off SVG. If the design calls for a non-Phosphor icon, evaluate whether a Phosphor alternative is acceptable before committing a custom asset.

  • Don't use Icons for brand marks. Logos and brand-specific illustrations are static SVG assets, not icon-system components.
  • Don't use Icons without semantic context. An icon-only button needs an aria-label; an icon next to text doesn't.

Accessibility

  • Iconify icons render <svg aria-hidden="true"> by default — appropriate for decorative use next to text.
  • For icon-only triggers (icon-only buttons), pair with IconButton which adds the required aria-label.
  • For meaningful icons that aren't paired with text, set aria-label directly on the surrounding element.

On this page