Register react-icons, lucide or hand-written SVGs with IconProvider, type-check the new names with IconLibraryOverrides, and replace the icons Once UI components draw.
Once UI 2.0 ships its own icons and lets you register more. Add them through IconProvider and teach TypeScript the new names, so a typo fails the build instead of rendering nothing.
What ships in the box
Once UI 2.0 no longer depends on an icon package. The SVG data for the built-in set is inlined in @once-ui-system/core, and it covers everything the components themselves draw: chevrons, check, close, info, warning, danger, search and so on.name on Icon is typed as IconName, a real union of those names. Before 2.0 the registry was typed Record<string, IconType>, so any string compiled and a typo only showed up as a blank space and a console warning. In 2.0 an unknown name is a type error.
Add your own icons
An icon is anything that renders an SVG and takes no props. Once UI never passes any. That means components from react-icons, lucide, heroicons, or an SVG you wrote yourself all work.Keep them in one file and hand that object to IconProvider:Your icons are merged over the built-in set, so you only list what you add or change.
Teach TypeScript the new names
Registering icons at runtime does not change the IconName type. Without one more step, <Icon name="rocket" /> renders fine but fails type-checking. Extend the union by merging into IconLibraryOverrides, right under the object:Because the interface is derived from the object, the two can't drift. Add an icon and its name type-checks straight away. Remove one and every place that still uses it becomes a build error, which is the point.Two things not to do:
Don't annotate the object as Record<string, IconType>. That widens the keys to string, IconName collapses back to string, and typos get through again.
<Icon name="check" onBackground="success-medium" />
<Icon name="chekc" /> // type error in 2.0
Don't write the names out by hand in the interface. The list will fall behind the object.
Replace a default icon
The components use the same registry. To swap a chevron, or the light, dark and computer icons the theme switcher draws, register your component under the same key:
Every component that asks for chevronDown now gets yours. This is the cleanest way to make Once UI match an icon set you already use elsewhere.
Resolve a name yourself
For rendering, use Icon. When you need the component behind a name, for example to fall back when a name comes from data, useIcons() returns the merged library:
const { icons } = useIcons();
const known = Object.keys(icons);
<Icon name={known.includes(name) ? name : "info"} />
useIcons() does not throw outside a provider. It returns the built-in set, so a component that only needs default icons works with no provider in the tree.
Write this / not this
Do
Avoid
`IconProvider icons={iconLibrary}`
Importing raw SVG components into every file
`IconLibraryOverrides` derived from the object
`Record<string, IconType>` on the registry
Same key to replace a default
Wrapping components to hide their icon
`<Icon name="rocket" />`
`<HiOutlineRocketLaunch />` inline next to Once UI icons
More design tips
The full reference, including the provider props, is in the IconProvider docs.