@primitiv-ui/icons
v0.1.40
Published
Fill-based SVG icon library for the Primitiv ecosystem. Icons inherit currentColor, scale via a size prop, accept all native SVG attributes, and tree-shake cleanly.
Readme
@primitiv-ui/icons
Fill-based SVG icon library for the Primitiv ecosystem. Icons inherit currentColor, scale via a size prop, and accept all native SVG attributes. Zero styles, zero runtime overhead, full tree-shaking.
Usage
Within the Primitiv workspace, import directly — no build step required:
import { Check } from "@primitiv-ui/icons";
// Default size (24px)
<Check />
// Custom pixel size
<Check size={16} />
// Rem-based size
<Check size="1rem" />
// Tailwind color via currentColor inheritance
<Check className="text-green-500" />
// Accessible (not decorative)
<Check aria-label="Confirmed" />Props
All icons share the same props via IconProps:
| Prop | Type | Default | Description |
|---|---|---|---|
| size | number \| string | 24 | Sets both width and height. Accepts pixel numbers (16) or CSS strings ("1rem"). |
| className | string | — | Applied to the <svg> element. Use Tailwind's text-* utilities to set currentColor. |
| aria-label | string | — | Makes the icon accessible to screen readers. When absent the icon is aria-hidden="true" (decorative). |
| fill | string | "currentColor" | Override the fill colour directly. |
| ref | Ref<SVGSVGElement> | — | Forwarded to the underlying <svg> element. |
All other SVG element attributes are accepted and forwarded.
Icons
| Icon | Import |
|---|---|
| ArrowLeft | import { ArrowLeft } from "@primitiv-ui/icons" |
| ArrowRight | import { ArrowRight } from "@primitiv-ui/icons" |
| Bell | import { Bell } from "@primitiv-ui/icons" |
| Bold | import { Bold } from "@primitiv-ui/icons" |
| Calendar | import { Calendar } from "@primitiv-ui/icons" |
| Check | import { Check } from "@primitiv-ui/icons" |
| ChevronDown | import { ChevronDown } from "@primitiv-ui/icons" |
| ChevronLeft | import { ChevronLeft } from "@primitiv-ui/icons" |
| ChevronRight | import { ChevronRight } from "@primitiv-ui/icons" |
| ChevronUp | import { ChevronUp } from "@primitiv-ui/icons" |
| Close | import { Close } from "@primitiv-ui/icons" |
| Copy | import { Copy } from "@primitiv-ui/icons" |
| Delete | import { Delete } from "@primitiv-ui/icons" |
| Download | import { Download } from "@primitiv-ui/icons" |
| Edit | import { Edit } from "@primitiv-ui/icons" |
| Error | import { Error } from "@primitiv-ui/icons" |
| ExternalLink | import { ExternalLink } from "@primitiv-ui/icons" |
| Eye | import { Eye } from "@primitiv-ui/icons" |
| EyeOff | import { EyeOff } from "@primitiv-ui/icons" |
| File | import { File } from "@primitiv-ui/icons" |
| Filter | import { Filter } from "@primitiv-ui/icons" |
| Folder | import { Folder } from "@primitiv-ui/icons" |
| Grid | import { GridIcon } from "@primitiv-ui/icons" — exported as GridIcon, see below |
| Home | import { Home } from "@primitiv-ui/icons" |
| Image | import { Image } from "@primitiv-ui/icons" |
| Info | import { Info } from "@primitiv-ui/icons" |
| Italic | import { Italic } from "@primitiv-ui/icons" |
| Link | import { Link } from "@primitiv-ui/icons" |
| List | import { List } from "@primitiv-ui/icons" |
| Mail | import { Mail } from "@primitiv-ui/icons" |
| Maximize | import { Maximize } from "@primitiv-ui/icons" |
| Menu | import { Menu } from "@primitiv-ui/icons" |
| Minimize | import { Minimize } from "@primitiv-ui/icons" |
| Minus | import { Minus } from "@primitiv-ui/icons" |
| Moon | import { Moon } from "@primitiv-ui/icons" |
| Pause | import { Pause } from "@primitiv-ui/icons" |
| Play | import { Play } from "@primitiv-ui/icons" |
| Plus | import { Plus } from "@primitiv-ui/icons" |
| Search | import { Search } from "@primitiv-ui/icons" |
| Settings | import { Settings } from "@primitiv-ui/icons" |
| Share | import { Share } from "@primitiv-ui/icons" |
| Sort | import { Sort } from "@primitiv-ui/icons" |
| Success | import { Success } from "@primitiv-ui/icons" |
| Sun | import { Sun } from "@primitiv-ui/icons" |
| Underline | import { Underline } from "@primitiv-ui/icons" |
| Upload | import { Upload } from "@primitiv-ui/icons" |
| User | import { User } from "@primitiv-ui/icons" |
| Warning | import { Warning } from "@primitiv-ui/icons" |
Adding icons from Figma
Export the icon at 24 × 24 px (the
mdcanonical size) as an SVG from Figma.Drop the
.svgfile intoicons/svg/, using kebab-case for the filename (e.g.arrow-right.svg).Run the generator:
pnpm generateReview the generated component in
src/icons/. The generator optimises paths via SVGO and converts hyphenated SVG attribute names to JSX camelCase. Hand-edit the output if needed — the generated files are committed source, not disposable artifacts.Add a row to the Icons table in this README.
Write a smoke test in
src/icons/<Name>.test.tsx(seeCheck.test.tsxas a template).
The five design sizes (xs=16, sm=20, md=24, lg=32, xl=48) are all driven by the size prop at runtime — only the md SVG needs to be exported from Figma.
Exported-name overrides
An icon's exported name normally comes straight from its filename, which is what
keeps the SVG asset, the Figma glyph and the React export in lockstep. One icon
is an exception, via NAME_OVERRIDES in scripts/generate.ts:
| Glyph / SVG / Figma | Exported as |
|---|---|
| grid | GridIcon |
Grid is also a registry layout component (RFC 0022), so a consumer importing
both in the same module gets a duplicate-identifier error that fails the build
outright — which is exactly how this was found. Renaming the asset to
grid-icon.svg would fix it too, but it pushes a redundant -icon suffix onto
the SVG and the Figma glyph, where it reads as a mistake. Overriding only the
exported symbol leaves both of those named grid, so nothing needs renaming
in Figma.
Only add an override for a genuine collision, never for taste — every entry is a place where the code name and the design name can drift.
List is the same shape of collision and is deliberately not overridden.
There is a registry list component too, but nothing imports both in one module
today, and renaming a published export is a breaking change that should not be
made speculatively. If you hit it, either alias at the import site
(import { List as ListIcon } from "@primitiv-ui/icons") or add the override
here and take the break knowingly.
Architecture
icons/svg/*.svg ← source files from Figma (committed)
↓ pnpm generate
src/icons/*.tsx ← generated components (committed, reviewable)
src/IconBase.tsx ← shared SVG wrapper (sets viewBox, fill, aria-hidden)
src/types.ts ← IconProps interface
src/index.ts ← re-exports everythingIconBase is exported for advanced use cases (e.g. building custom icon wrappers) but is not needed for normal icon consumption.
Testing
# Run all icon tests once
npx vitest run
# Watch mode
npx vitest
# With coverage
npx vitest run --coverage