Amended 2026-10-24 by 0322: a declaration
writes the generated constant,
icon: Icons.House, where decision 1 has it write the string "house".
The IconName union of decision 2 stays, as the type behind the constants, and gen still checks each
name against it. The Icons.* form that this page rejects was an import of an icon component, and that
stays rejected: a constant is a value that gen emits. Decisions 3 to 6 stand.Enforcement of this note: planned — gen emission of the constants and the lint rule of 0322 decision 6.Context
Navigation entries, KPI tiles, banners and buttons all show an icon. The v3 proposals and the template imported an icon component into each declaration (import { Icons } from "@stackra/ui/icons", then
icon: Icons.Receipt). That ties every declaration to one icon library and one renderer, and it puts a
component import into a file that is otherwise data. A declaration is read by gen, by the manifest and by
the web and native clients, and none of them needs a component to do so.
Decision
- A declaration references an icon only by its
IconName, a string. No declaration imports an icon component. Examples arenavigation: { group, icon: "receipt", order: 20 }andd.kpi("revenue").icon("banknote"). IconNameis a string union. It is generated from Lucide 1.54.0, which is pinned, and it adds the Stackra aliases. It is exported from@stackra/icons/contracts.@stackra/uiresolves a name to a drawing on each platform:lucide-reacton the web andlucide-react-nativeon native. The map from names to drawings is the only place that knows the library. Swapping the library changes that map in@stackra/iconsand nothing else.- Gen validates every icon name used in a declaration against
IconName, and emits a registry of the names that the build uses. A bundle holds the drawings of the used names only. - A member’s own icons, in its
assets/icons/folder, join the set under the namespace form<namespace>::<name>, for examplebilling::invoice. They follow the asset rules of ADR 0234, and an override of one replaces the file whole (ADR 0306 rule 4). - The package is
@stackra/iconsin the design-system category (ADR 0302). It has acontractsentry, which holds the name union, and a platform entry per renderer.
Consequences
- A declaration is data that every target reads the same way. A reviewer sees the name and nothing else.
- A name that does not exist fails at gen, so a typo does not render an empty square.
- The icon library can change in one file, and the bundle size follows the names used.
- The
Icons.*form in the earlier proposals and the template is not used. The template is converted in the template pass (STA-344).
Enforcement
- planned — gen validation of icon names against
IconName, and the used-names registry. The work item is not yet open in Linear. - planned — the
@stackra/iconspackage, which is not built yet (ADR 0302 places it, and its work item follows the design-system build).