Skip to content

Icons

Feature logic never references an icon — an icon is pure presentation. @evolve-storefront/ui owns one module mapping semantic names to SVG components, and that map is the single override seam. Components render <Icon name="shoppingList" />, never a scattered import { ShoppingBag } from "lucide-react".

Name icons by role, not shape: shoppingList and remove, not shopping-bag and trash. A brand that wants a heart instead of a bag remaps one entry and the meaning stays stable everywhere.

[data-component="icon"] {
@apply size-5 text-primary;
}

Components that render an icon accept it as a prop. A ReactNode crosses the RSC boundary fine.

<AddToShoppingListButton icon={<HeartIcon />} />

Swap an icon, or the whole set, everywhere

Section titled “Swap an icon, or the whole set, everywhere”

Spread the defaults and override the keys you want:

// src/ui/icons.ts
import { icons as base } from "@evolve-storefront/ui/icons";
import { BrandList } from "#icons";
export const icons = { ...base, shoppingList: BrandList };
export type IconName = keyof typeof icons;

Pointing packages at that file means aliasing the subpath, which is the escape hatch — see the alias band in the parent skill before doing it. Switching icon library outright is the one case that genuinely earns it: it is a markup change, it applies build-wide by nature, and it touches no feature package and no page.

Avoid an SVG sprite sheet (awkward per-icon tree-shaking and override) and a runtime context icon provider (unreadable in Server Components). Per-icon React components behind the semantic map give both tree-shaking and clean overrides.