Foundations

Icons.

Different shapes. A shared language.

Bring your own SVG icons, keep their personality, and share Dixy’s sizing, semantic colors and accessibility contract.

Your icons. A shared foundation.

Lucide for the baseline. Phosphor for another personality. Your own SVGs whenever the product needs them.

Open the Icon playground

Reuse the tokens we already have

Icon sizing lives in the sizing foundation, and icon foregrounds live in the color foundation. We keep those names: size.icon.sm and color.icon.secondary. The new 2xl step extends the existing size scale to 48px; it does not create a second icon-size namespace.

xs12px / 0.75rem
sm16px / 1rem
md20px / 1.25rem
lg24px / 1.5rem
xl32px / 2rem
2xl48px / 3rem
icon-tokens.css
/* Existing canonical token names */
--dixy-size-icon-sm: 1rem;
--dixy-size-icon-md: 1.25rem;
--dixy-size-icon-2xl: 3rem;

/* Foregrounds follow appearance and the semantic color system. */
color: var(--dixy-color-icon-secondary);
color.icon.primary
color.icon.secondary
color.icon.disabled
color.icon.success
color.icon.danger
color.icon.warning
color.icon.information
color.icon.discovery

Standalone icons default to 20px and inherit currentColor. Set color="primary" or another explicit role for a standalone foreground. Inside a Button, inheritance preserves the control’s contrasting foreground; the default icon size follows its control size. An explicit Icon size always wins. The disabled color role is visual; disabling an action belongs to its Button.

Composition keeps each pack honest

The render element receives common SVG props, merged classes/styles/events, and SVG refs. Pack-specific settings stay on the actual pack component. Dixy keeps the original viewBox and never imposes a global stroke width or fill.

example.tsx
import { Icon } from "@dixy-ui/react";
import { Search } from "lucide-react";
import { HeartIcon } from "@phosphor-icons/react/dist/ssr/Heart";

<Icon render={<Search />} size="sm" color="secondary" />
<Icon render={<HeartIcon weight="duotone" />} size="lg" color="danger" />

Use a component that renders one SVG root and forwards className, style, SVG attributes and ref. A local adapter can translate those common props for a pack with a different API. Use currentColor artwork for semantic colors; hard-coded fills or an explicit pack color intentionally keep their own color. A component returning a span, image or font glyph needs a separate adapter; this SVG contract does not cover it automatically.

thin
light
regular
bold
fill
duotone

These are Phosphor’s six actual artwork variants. They are not fabricated with stroke-width overrides. Small thin icons can be difficult to perceive; choose regular or heavier for functional controls.

Give the action the accessible name

Ready to publish
example.tsx
<Button>
  <Icon render={<Search />} />
  Search projects
</Button>

<IconButton aria-label="Add to favorites">
  <Icon render={<HeartIcon />} />
</IconButton>

{/* Meaningful standalone image; otherwise omit label. */}
<Icon render={<Check />} label="Changes saved" color="success" />

Icon defaults to aria-hidden and has no keyboard stop. A nonempty label exposes a role="img" with that accessible name. The wrapper normalizes these attributes after composition so a pack’s defaults cannot hide a named image or duplicate decorative announcements. Keep label off icons that accompany visible text. An icon’s 16px artwork and its button’s interaction target are different sizes.

A default pack without a mandatory dependency

IntegrationCurrent evidenceInstall ownership
Lucide ↗Docs baseline; inline SVG composition exercised in the playground.App dependency, static imports.
Phosphor ↗SSR entry, six weights and interactive rendering exercised here.App dependency; individual SSR imports.
Custom SVGViewBox, refs, events, naming and fill/stroke preservation covered by tests.Your own component.
Iconify ↗Optional integration guidance; the catalog explorer and adapter are future work.App chooses a renderer and icon data; core imports none.
Heroicons, Tabler, HugeiconsPotential adapters through the SVG contract; not yet tested or claimed as official integrations.Install and verify each selected package.

Lucide and Phosphor are installed in the documentation app, not the Dixy package. Use direct icon imports so bundlers can remove unused artwork. The core has no global name registry, icon catalog or icon API request. Iconify name-based rendering can load data at runtime; its docs recommend supplied icon data when immediate server rendering is required. Treat a future explorer separately from essential application icons.

Primer’s icon guidance reinforces consistent sizes, recognizable meaning, functional foregrounds and text alongside icons. An arbitrary pack may have specially drawn optical sizes; choose those variants deliberately rather than stretching every glyph to every size. Check the selected pack’s license before distribution.