Roadie uses Phosphor Icons at the Bold weight. The thicker strokes pair with the system's rounded, approachable visual language and stay legible at small sizes.
Bold weight provides thicker strokes that are more legible at small sizes and create a confident, approachable feel. Here are some commonly used icons in the system.
Four fixed tiers map to component contexts. Set an icon's size with a Tailwind
size-* class in className, never Phosphor's size prop. On the docs site,
each tier is drawn at its class with its size in pixels.
size-312pxsize-416pxsize-520pxsize-624px| Tier | Class | Use for |
|---|---|---|
| XS | size-3 | Badges, tags, compact elements, and chevrons in small buttons |
| SM | size-4 | Buttons, and inline with body text (the default) |
| MD | size-5 | Navigation and standalone actions |
| LG | size-6 | Page headers, feature cards, and hero sections |
Badge, Button, IconButton, and IconTile size the icons inside them, so an icon
there needs no size class. Badge sizes its icon to the text (1em). Button
and IconButton size an icon to the button, unless the icon has a size-*
class of its own: 16px in a Button and 20px in an IconButton by default.
IconTile sizes its icon to the tile.
Three weights are used in the system. Bold is the default for everything.
Fill is reserved for active or selected states. Duotone is for large,
decorative icons in a tile or graphic above 48px. Use it on feature surfaces,
in an IconTile larger than lg, and in an EmptyState tile at its default
size, where a bold
outline alone looks hollow.
| Weight | When to use |
|---|---|
bold | The default for all icons |
fill | Active or selected states only |
duotone | Decorative icons in a tile or graphic above 48px, such as an IconTile |
Navigator is the exception. Its destinations render duotone at 24px. Navigator applies the weight itself, so pass it a bare icon.
Navigation items use Bold when inactive and Fill when active.
Frame an icon in an IconTile when it needs to stand on its own, such as
leading a dialog, a list row, or an empty state. The tile sizes and centres
the icon for you, so pass a bare icon as children with no size class.
Tile the item, not the action. Inside buttons, menu items, tabs, badges, and
inputs, use a bold icon with no tile, at the size the control sets or
size-4 where it sets none. See Icon Tile.
Tiles are the main place weight='duotone' is welcome. Use weight='bold' up
to a 48px tile (lg), then switch to duotone above 48px, where a bold outline
can look hollow on the larger surface. Keep Fill reserved for active states
as elsewhere.
Icons inherit currentColor by default. Use text-* utilities to set icon
colour, or let them inherit from a parent. An intent only sets variables, so
it colours an icon through a text-* utility on the icon or its parent, such
as a Badge.
Phosphor exports each icon with an Icon suffix. Always use the suffixed export. The bare name is deprecated.
import {HeartIcon,StarIcon} from '@phosphor-icons/react/ssr'
Do
Import the Icon-suffixed export directly.
import {Heart,Star} from '@phosphor-icons/react/ssr'
Don’t
Bare names are deprecated and can collide with component or variable names.
Phosphor's /ssr entry point doesn't use React context, so it works in server components.
// Server component (no 'use client')import {HeartIcon} from '@phosphor-icons/react/ssr'
Do
Use @phosphor-icons/react/ssr in server components.
// Server component (no 'use client')import {HeartIcon} from '@phosphor-icons/react'
Don’t
The standard entry reads React context, which server components can't use, so it fails there.
weight='bold' explicitly. Phosphor's default is Regular, not
Bold.aria-label on icon-only buttons. IconButton enforces it as a
required prop.currentColor. Use text-* utilities for colour, not inline
styles or Phosphor's color prop.@phosphor-icons/react/ssr in server components. Only use
@phosphor-icons/react in files with 'use client'.Icons are most effective when paired with text. Use icon-only buttons only when the action is universally understood, and always provide an aria-label.
Do
Pair icons with visible text. For icon-only buttons, use IconButton,
which requires aria-label.
Don’t
Don't use a button with only an icon and no label or aria-label. Screen
readers won't know what the button does.
All icons use weight='bold'. Don't mix weights, which breaks visual harmony.
Do
All icons at Bold weight for a consistent stroke width.
Don’t
Mixing weights creates visual inconsistency. Regular, Thin, and Light look out of place next to Bold.
Fill weight signals that something is selected or active. Don't use it as the default.
Do
Fill for the active item, Bold for everything else.
Don’t
Fill on inactive items removes the visual distinction for the active state.
Duotone adds depth at large sizes but muddies legibility when small.
Do
Use weight='duotone' in a tile or graphic above 48px. The two-tone fill
reads as intentional depth on feature surfaces and in a large IconTile.
Don’t
Don't use duotone for small inline or UI icons. The lighter secondary
layer turns muddy at small sizes. Use weight='bold' instead.
Use the sizing scale to keep icons proportional to their surroundings.
Do
Let components size icons, or use the tier for the context.
Don’t
Oversized icons next to small text look unbalanced. Match the icon tier to the text size.