Iconography
Lucide icons: one per meaning, how big, what color, and when an icon is named or hidden.
Every icon is Lucide, drawn with its own 2px line. One icon stands for one meaning across every app. An icon either sits beside words and stays silent, or stands alone and is named. Company logos are not icons: they come from BrandMark.
Lucide
- Import from
lucide-react(lucide-react-nativein the mobile app). No other icon set, and no hand-drawn SVG for something Lucide has. - Keep Lucide's 2px line. Don't pass
strokeWidth; the only exception is a tick inside something tiny (Checkbox draws its 12px tick at 3px so it doesn't look faint). - Inside a Button, IconButton or Tag, pass a bare icon: the component sizes it. A size class on it opts out.
- A new icon you draw yourself sits on Lucide's 24px grid with a 2px line, round ends and corners, in
currentColor.
import { MapPin, Plus } from "lucide-react";
// Inside a button: bare, the button sizes it
<Button><Plus aria-hidden="true" />Make intro</Button>
// Beside words: sized to the text, hidden from screen readers
<span className="inline-flex items-center gap-1.5 text-13 text-[var(--text-muted)]">
<MapPin aria-hidden="true" className="size-3.5" />
Lagos
</span>One icon per meaning
The icons the apps use most, by what they mean. Use the same icon for the same meaning everywhere, and never one meaning's icon for another.
| Meaning | Use | Not | |
|---|---|---|---|
| Add or create | Plus | CirclePlus: the circle adds nothing | |
| Close, clear, remove from a list | X | CircleX: a circled X reads as failed | |
| More actions on a row or record | EllipsisVertical (was MoreVertical) | Ellipsis: ActionMenu uses the upright dots | |
| Edit | Pencil | SquarePen: two pencils for one meaning | |
| Delete | Trash (was Trash2) | X: X closes, it doesn't delete | |
| Copy; a tick once copied | Copy then Check | Clipboard: a clipboard is pasting | |
| Opens another site or a new tab | ExternalLink | ArrowUpRight: reads as “go on” or a number going up | |
| Go on: the next step, see all | ArrowRight | ArrowUpRight: that's for numbers going up | |
| Back to the page before | ArrowLeft | ChevronLeft: that pages back through a list | |
| Opens a menu or a section | ChevronDown | – | |
| Goes into a row, or the next page of a list | ChevronRight | – | |
| Working on it | LoaderCircle (was Loader2) | Loader: the spoked one; use one spinner | |
| Sync, or try again | RefreshCw | RotateCw: two arrows for one meaning | |
| Succeeded | CircleCheck (was CheckCircle2) | CircleCheckBig: two ticks for one meaning | |
| Error | CircleAlert (was AlertCircle) | CircleX: use one error icon | |
| Warning; can't be undone | TriangleAlert (was AlertTriangle) | CircleAlert: that's an error | |
| More about this | Info | CircleQuestionMark: use one hint icon | |
| Done by AI | Sparkles | WandSparkles: use one AI icon; Bot: Bot is the agent itself, not what it did | |
| People, a network; one person | Users then User | Contact: a card, not a person | |
| Introduce, or add a person | UserPlus | Handshake: that's a deal done | |
| A company or fund | BuildingComplex (was Building2) | Briefcase: a briefcase is a job | |
| A job or role | Briefcase | – | |
| Search | Search | – | |
| Email; Send to send it | Mail then Send | AtSign: @ is a mention | |
| A link to copy or share | Link2 | – | |
| A place | MapPin | – | |
| A date or a meeting | Calendar | – | |
| Private, or only some people can see it | Lock | – | |
| Settings | Settings | – |
Every icon
Every icon in Lucide, read from the installed package. Search by what you need; Bridge's own icon for that meaning comes first. Icons that already mean something say so.
Click an icon to copy its import.
Every Lucide icon
When nothing in the table fits
- Search here (or ask the agent's
find_icon) for a Lucide icon that isn't already taken for another meaning. - Add the new meaning to the table in the same change (
content/foundations/iconography/meanings.ts), so everyone uses the same icon for it from then on. - If Lucide has nothing, draw one on its 24px grid with a 2px line and add it to the package, never to one app. A company logo goes in BrandMark.
Sizes
Two rules give every size. Beside words, an icon is 2px bigger than the text. Inside a square or a circle, it's half the shape's width.
Beside words
| Text | Icon | Class |
|---|---|---|
| 12–13px: meta, table rows, small buttons, tags | 14px | size-3.5 |
| 14px: body, menus, fields, the default button | 16px | size-4, the default |
| 16px: card titles, the large button | 18px | size-[18px] |
In a shape
| Where | Icon | Set by |
|---|---|---|
| A tiny control: the × on a tag, sort arrows, the checkbox tick | 12px | size-3 |
| Card's 36px header square | 18px | Card icon |
| ConfirmDialog's 40px warning circle | 20px | ConfirmDialog |
| DataState's 48px empty and error circle | 24px | DataState |
- Nothing is bigger than 24px. A larger picture is an illustration, not a scaled-up icon.
- Beside more than one line of text, line the icon up with the first line (
mt-0.5), not the middle of the block.
Color
Icons take their color from what they sit in. They're quiet at rest, darken on hover, and turn blue only when something is on or picked.
| When | Color | For example |
|---|---|---|
| Beside words | The words' color: it inherits | A muted icon in a muted meta row |
| Controls at rest | --text-muted | Icon buttons, filter chevrons, row actions |
| Hovered | --text-primary | An icon button under the pointer |
| On, or picked | --primary | An active filter, the sorted column's arrow |
| Section and feature icons | --primary, in Card's colored square | Card headers |
| Empty states | --text-disabled | DataState's empty circle |
| A result | --success, --error, --warning-text, beside the word | A tick beside Sent, a warning beside Failed |
| On a filled button | White: it inherits | The primary button's icon |
Named or hidden
An icon beside words is hidden from screen readers, because the words already say it. An icon on its own is the only name its button has, so it's named. Never neither.
- Beside a label:
aria-hidden="true". - On its own: use IconButton, which needs an
aria-label. Name the action ("Copy email"), not the picture ("Copy"). - Where the icon alone could mean more than one thing, wrap it in Tip with the same words.
- When the action flips, the name flips with the icon: "Show details" becomes "Hide details".
- A result icon never stands alone: a tick travels with Sent, a warning with Failed.
Icon squares
Where an icon names a section or a topic, it sits in Card's header square: 36px, 8px corners, tinted blue, green, amber or purple by topic, with an 18px icon.
Intros this week
Who you introduced, and who said yes.
- Squares are for topics. A round shape is a person (Avatar) or an empty state (DataState).
- One icon per square, no text inside.
Company logos
Logos aren't icons and Lucide has none. Use BrandMark for LinkedIn, Google, Microsoft, Apple, WhatsApp, Telegram and Chrome: their own colors, at icon size.
- Never recolor a logo to match the page. LinkedIn, WhatsApp and Telegram may be one color (
mono) in a quiet row of details. - A logo means the company: signing in with it, going to it, or something that came from it. For an action like sharing, use a Lucide icon.
No emoji
- No emoji in labels, buttons, headings, toasts, empty states or sample data.
- What people write themselves (messages, notes, bios) keeps its emoji.
Rules
One icon set, one icon per meaning
Every icon is Lucide at its own 2px line. Each meaning has one icon, listed on Iconography; a meaning that isn't listed gets a Lucide icon nobody else uses, added to the list in the same change. No other icon set, no emoji in the interface, and no hand-drawn company logos: BrandMark draws them.