IconsExperimental
Any icon works in Bones: every component takes icons as children, so your existing set drops straight in. @usebones/icons adds a typed vocabulary on top: semantic names that fail to compile when misspelled, size from the same tokens as every control, and swap sets in one place. The package is experimental: the vocabulary API may still change between releases while the interface tier settles what it needs from it.
pnpm add @usebones/iconsUse an icon
Names are typed as IconName, so a typo fails at compile time, for people and coding agents alike. Icons render aria-hidden; the control around them carries the accessible name.
import { Icon } from "@usebones/icons";
import { Button } from "@usebones/react";
<Button iconOnly aria-label="Search">
<Icon name="search" />
</Button>Grow the vocabulary
Declare your glyphs once and their keys become names: fifty icons is fifty lines in one object plus a single type line, and only the glyphs you import ship. A registered name with no glyph renders nothing and warns once in development.
// icons.tsx
import { defineIcons, IconProvider, type IconNamesOf } from "@usebones/icons";
import { Rocket, ThumbsUp } from "lucide-react";
export const icons = defineIcons({ rocket: Rocket, "thumbs-up": ThumbsUp });
declare module "@usebones/icons" {
interface IconRegistry extends IconNamesOf<typeof icons> {}
}
<IconProvider icons={icons}>
<App />
</IconProvider>
<Icon name="rocket" />Swap the set
The same provider overrides built-in names, so pointing the app at a different set is one object at the root; anything you leave out keeps the default. The toggle in this site's sidebar is exactly that.
<IconProvider icons={{ search: MySearchGlyph, bell: MyBellGlyph }}>
<App />
</IconProvider>Built-in names
The names Bones-built UI may ask for, with Lucide defaults; when you swap sets, these are the glyphs to supply. Components hand-roll their own tiny structural glyphs (chevrons, checks), so nothing here is required by a component.
align-leftalign-centeralign-rightarrow-downarrow-leftarrow-rightarrow-upbellboldcheckchevron-downchevron-rightclosecopycredit-cardinfoitalicloadermenumoonsearchsununderlineuser
Props
Everything an SVG accepts passes through, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
Icon.name | IconName | – | Which glyph to render; a built-in name or one you registered. |
Icon.size | number | – | Pins an exact pixel size; by default the icon follows --ub-icon-size (16px, 14px in compact contexts). |
IconProvider.icons | Partial<IconSet> | – | Glyphs by name: overrides for built-in names and the glyphs for names you added; omitted names fall back to the default set. |
defineIcons(icons) | (icons) => icons | – | Declares your glyphs once with their keys preserved as types; pass the result to IconProvider. |
IconNamesOf<typeof icons> | type | – | The registry entries for a defineIcons object; extend IconRegistry with it. |
Sizing follows the two-size system described in Sizes.