Icons
Any icon set on Iconify, pinned to a version and compiled into your app one icon at a time.
Declare a set
An icon set is a dependency, so it is declared like one — by name and version, in whitehall.toml:
[icons]
lucide = "1.2.121"
ic = "1.2.4" The name is the set's Iconify prefix and the version is its @iconify-json package version, which makes it a lockfile: two machines building the
same commit get byte-identical icons.
Draw one
Name the set, then the icon:
<Icon name="lucide:heart" />
<Icon name="ic:baseline-calendar-today" size={20} color="primary" /> Only the icons you name are compiled in. A set is tens of thousands of glyphs; an app that draws six ships six.
<Icon> — <IconButton icon="ic:baseline-search" /> reads the set the same way.Import a set
A file that draws several icons from one set can import the set and drop the prefix. Icon names become PascalCase:
import $icons.lucide
<Icon name={lucide.Heart} />
<Icon name={lucide.Star} /> Or import single icons, which reads best when a file draws one or two:
import $icons.lucide.Heart
import $icons.ic.BaselineSearch
<Icon name={Heart} />
<Icon name={BaselineSearch} /> Two sets can have an icon of the same name. Per-icon imports are the one form where that
collides, and Kotlin's own as resolves it:
import $icons.lucide.Home as LucideHome
import $icons.ic.Home Names
Iconify names are kebab-case and the identifier is its PascalCase form, so the hyphenated spelling is only valid inside a string:
| Iconify name | As a string | As an identifier |
|---|---|---|
heart | "lucide:heart" | lucide.Heart |
baseline-calendar-today | "ic:baseline-calendar-today" | ic.BaselineCalendarToday |
calendar-check-2 | "lucide:calendar-check-2" | lucide.CalendarCheck2 |
PascalCase is not reversible, so two names can want the same identifier — arrow-up-1-0 and arrow-up-10 both want ArrowUp10. When
that happens neither gets one, because picking a winner would make lucide.ArrowUp10 mean something you cannot see from where it is written. The string
form still reaches both.
A name known only at runtime
An icon chosen by a value the compiler cannot see — a field on a fetched record, a user setting — has to be listed, because nothing in the source says which glyph to compile in:
[icons]
lucide = { version = "1.2.121", include = ["heart", "star", "bookmark"] } <Icon name={item.icon} /> // "lucide:star", decided at runtime A name that reaches this and is not in include draws nothing and logs why, since
the string does not exist until the app runs. An include entry naming an icon the
set does not have is a build error rather than an icon that silently never appears.
Errors
| Rule | When |
|---|---|
icon-needs-a-set | name="home" — a project can declare several sets, so the name has to say which
one |
icon-set-not-declared | name="lucide:heart" with no lucide in [icons] |
icon-not-in-set | The set is declared but has no icon by that name |
Finding a version
Sets are published to npm as @iconify-json/<prefix>:
npm view @iconify-json/lucide version
npm view @iconify-json/ic version Whitehall fetches that tarball once per version per machine and caches it under ~/.whitehall/icons, so a clean build after the first is offline.
<Checkbox>, the chevron on a <Select> — carry their own glyphs and need no [icons] table.