Propel

Iconography

The generated icon set — how icons are sized, themed, named, and added, and every glyph in one place.

Propel ships 934 icons across 18 categories, published as their own entry point. Every icon is a React component, sized to the text it sits beside, and colored by the surrounding text color rather than a value baked into the file.

import { SearchFilled } from "@makeplane/propel/icons";

<SearchFilled />;

Import icons individually, never as a namespace. Each icon is its own module, so a build only includes the ones you name — import * as icons defeats that and pulls in all 934.

Icons carry no "use client" boundary. They are static SVG with no state, hooks, or event handlers, so they render on the server inside a React Server Component without shipping any JavaScript to the browser.

Sizing and color

An icon renders at 1em and inherits currentColor, so it takes both from its context rather than from props. Set the size with a font-size utility and the color with a text utility on the icon or anything above it — there is no size or color prop to reach for. The exception is StateGroupIcon: it takes a size prop that sets width and height in pixels.

{/* 1rem, inherits the text color */}
<SearchFilled />

{/* Scaled and tinted by the surrounding text */}

<span className="text-body-lg-regular text-danger-strong">
<SearchFilled />
</span>

Every icon is aria-hidden by default, which is correct for the common case — an icon beside a label that already names the action. When an icon is the only content of a control, the control needs its own accessible name; put it on the control, not the icon.

<IconButton aria-label="Delete" icon={<Icon icon={DeleteFilled} />} />

Theming

Icons follow the active theme because they paint in currentColor rather than a fixed value. Two deliberate exceptions, and one refinement:

CategoryPaintWhy
everything elsecurrentColorFollows the surrounding text color, so one glyph works on every theme.
other-productsbrand paletteA third-party logo is wrong in any color but its own — Slack's four hues, Claude's terracotta, YouTube's red.
priority-{level}currentColor + var(--priority-unlit)A level is lit bars over dimmed ones. The lit bars follow the text color; the dimmed bars paint in the unlit token so they hold their weight in both themes.

The priority glyphs — PriorityUrgent, PriorityHigh, PriorityMedium, PriorityLow, PriorityNone — are the one two-tone family. Set the level color on the icon with its text-priority-* token and the unlit segment takes care of itself:

<PriorityHigh className="text-priority-high" />
<PriorityMedium className="text-priority-medium" />
<PriorityLow className="text-priority-low" />

Work item state

StateGroupIcon — exported from the same @makeplane/propel/icons entry — draws a work item’s state together with its progress. Pass stateGroup: backlog, unstarted, started, completed, or cancelled. started and unstarted render percentage as continuous progress: a solid outer ring advances clockwise from twelve while fifteen radial ticks disappear behind it. Values at or below 1 are fractions; values above 1 are percentages. It defaults to 100. size is xs 10px, sm 12px (the default), md 14px, lg 16px, xl 18px.

UnstartedGroupIcon and StartedGroupIcon are those two glyphs on their own. The static sets — cycles, initiatives, milestones, modules, and work items — sit in the gallery below.

import { StateGroupIcon } from "@makeplane/propel/icons";

<StateGroupIcon stateGroup="started" percentage={37} size="lg" />

The brand exemption is narrower than the category. It applies only to marks that genuinely carry a palette: a logo exported as a single flat neutral is a monochrome wordmark, not a palette, so it themes like any other icon. GitHub, X, Intercom, ChatGPT and Docker all fall in that group — hardcoding their near-black would leave them at roughly 1:1 contrast against the dark theme’s own near-black background, which is to say invisible.

Outside other-products, theming is enforced rather than encouraged: an icon left carrying a concrete color after generation fails the build instead of shipping unthemed. Plane’s own product marks under sub-brands get no exemption — they are themed like everything else.

Naming

Export names are derived mechanically from the source filename, so the name is predictable from the glyph rather than something to look up.

SourceExportRule
search-filled.svgSearchFilledkebab-case becomes PascalCase.
search-outline.svgSearchOutlineThe fill state is always last. An icon with a state ends in Filled or Outline, with no exceptions.
share-alt-filled.svgShareAltFilledalt marks a second variant of the same concept, and still leaves the state last.
404-outline.svgIcon404OutlineA digit-leading name gets an Icon prefix, since an identifier cannot start with a number.
formatting-and-editors/table-filled.svgTableEditorFilledWhen two categories claim one filename with different art, the later one takes a short category qualifier — before the state, never after it.

Adding an icon

src/icons/ is generated. Never hand-edit it: check:icons regenerates the tree and diffs it against what is committed, so an edit made by hand fails CI on the next run.

# 1. Drop the SVG into packages/propel/icons/<category>/ — directly in the
#    category folder; a stray or nested file fails the build rather than
#    being silently skipped.
# 2. Regenerate.
pnpm --filter @makeplane/propel gen:icons
# 3. Commit the SVG and the generated output together.

Generation writes to a scratch directory and swaps it in only on success, so a run that fails the color policy or hits a name collision leaves the committed tree untouched.

Two things the generator reports without failing, because it cannot tell a deliberate choice from a source mistake: an icon painting a rendering white (a Figma knockout, which halos on the dark theme), and groups of icons whose markup is byte-identical — usually a -filled and -outline pair cut from the same glyph. Run ICONS_REPORT_DUPES=1 pnpm gen:icons to list the latter.

The set

Search by export name, or filter by category. Click any icon to copy its import.

Showing 934 of 934 — click an icon to copy its import.

Placeholder · 1

Workspace features · 44

Sub brands · 8

Project features · 20

Layouts · 30

Formatting and editors · 90

Properties · 74

Actions · 166

Charts · 10

Arrows · 79

Miscellaneous · 347

Other products · 41

Status updates · 4

Cycle states · 3

Module states · 6

Milestone states · 3

Initiative states · 5

Work item states · 3