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 playgroundReuse 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.75remsm16px / 1remmd20px / 1.25remlg24px / 1.5remxl32px / 2rem2xl48px / 3rem/* 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.primarycolor.icon.secondarycolor.icon.disabledcolor.icon.successcolor.icon.dangercolor.icon.warningcolor.icon.informationcolor.icon.discoveryStandalone 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.
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.
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
<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
| Integration | Current evidence | Install 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 SVG | ViewBox, 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, Hugeicons | Potential 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.