Skip to main content
Executive Support by Beige Threat

Component inventory

One component shipped. Eight in flight. Twenty more catalogued and waiting their turn. The system grows component by component – never in a single push – and every one ships against the same contract before it’s marked done.

This page is the honest count. What you can use today, what’s coming next, and what we’ve decided we won’t build. If the answer to “is there a component for X?” isn’t here, the answer is no – and the proposal route at the bottom of this page is how we’d hear about it.

The component contract

A component is “shipped” when it satisfies all eight points below. Anything less is “beta” or “in progress” – useful labels because they tell you what’s safe to put in production and what isn’t. The contract is non-negotiable. Skipping a check to hit a deadline is how design systems quietly become inconsistent UI libraries.

The eight checks
Tokens only
No inline values

Every colour, spacing, radius, shadow, and motion value resolves to a token. Magic numbers fail review.

var(—es-color-teal-600)
All states
Default, hover, focus-visible, pressed, disabled, loading

Every interactive state is implemented and documented. Loading applies where the component can fire an async action.

6 states · documented per variant
Keyboard-complete
Tab, Enter, Space, Escape, Arrows

The component is fully operable without a mouse. Arrow keys apply where there's a list, menu, or radio group.

Pointer-free path from open to commit
WCAG 2.2 AA
Contrast, name/role/value

4.5:1 for text, 3:1 for non-text. Every interactive element has an accessible name, a role, and a current value where applicable.

Tested with VoiceOver, NVDA, JAWS
Reduced motion
prefers-reduced-motion honoured

Transitions shorten or disable when the user has asked for less motion. No component depends on animation to convey state.

Motion is a layer, not a load-bearing wall
Light + dark
Both modes bound to tokens

Switching mode never breaks contrast and never re-themes the component. Semantic tokens carry the load.

One source of truth, two surfaces
API contract
variant, size, state, content slot

The component exposes the same shape every other component does. Predictable props mean readable composition.

See the contract below
Docs page
Anatomy, props, examples

Every shipped component has a page on this site with a live anatomy diagram, the prop table, and at least three usage examples.

No docs, no ship

Status taxonomy

Five labels. They mean exactly what they say.

● Shipped

Meets the full contract. Safe to use everywhere. Breaking changes require a major version.

● Beta

Meets the contract minus full state coverage. Usable in production. The API can still shift.

● In progress

Actively being built. There’s an owner, a brief, and a target. Don’t depend on it yet.

● Planned

On the roadmap. The brief exists. No work has started. Sequencing is on this page.

● Out of scope

Intentionally excluded. The reason is on the page. Don’t propose it without reading first.

Inventory

Every component the system tracks, grouped by what it does. Names that link out have a docs page; the rest are catalogued but not yet authored. The “depends on” column is honest about prerequisites – nothing ships until its dependencies have.

Action

ComponentStatusDepends onDocs
Button● Shipped v1.0Colour, type, motion tokensView →
Icon button● In progressButton, iconography
Link● PlannedColour, focus tokens

Input

ComponentStatusDepends onDocs
Text field● In progressForm primitives, validationView →
Textarea● In progressText fieldView →
Select● In progressText field, popoverView →
Checkbox● In progressForm primitivesView →
Radio● In progressForm primitives, group navView →
Switch● PlannedForm primitives, motion
Slider● PlannedForm primitives, ARIA value

Display

ComponentStatusDepends onDocs
Card● PlannedSurface tokens, shadow
Tag / Pill● PlannedColour, type tokens
Badge● PlannedColour, type tokens
Avatar● PlannedImage, colour tokens
Tooltip● PlannedPopover positioning

Navigation

ComponentStatusDepends onDocs
Top nav● PlannedLink, menu, brand mark
Footer● PlannedLink, type tokens
Tabs● PlannedFocus, ARIA tablist
Breadcrumbs● PlannedLink
Pagination● PlannedButton, icon button
Side nav● PlannedLink, ARIA tree

Feedback

ComponentStatusDepends onDocs
Toast● PlannedARIA live region, motion
Banner● PlannedFeedback colour tokens
Inline alert● PlannedFeedback colour tokens
Empty state● PlannedType, button, illustration

Overlay

ComponentStatusDepends onDocs
Modal / dialog● PlannedFocus trap, scrim, motion
Sheet● PlannedModal, motion
Popover● PlannedAnchor positioning
Menu● PlannedPopover, ARIA menu

Data

ComponentStatusDepends onDocs
Table● PlannedType, pagination, menu
Definition list● PlannedType tokens
Stat block● PlannedType, colour tokens

Editorial

Editorial elements live in the typography and patterns pages, not as standalone components. They’re CSS classes on the long-form template – pull-quote, drop-cap, end-mark, caption – and they ride the same type tokens as everything else.

PatternStatusDepends onDocs
Pull-quote● Editorial patternType tokens
Drop-cap● Editorial patternType tokens, Freight Big
End-mark● Editorial patternIconography
Caption● Editorial patternType tokens

What “good” looks like

Two ways to wire up the same primary action. One satisfies the contract, the other quietly breaks it.

Do · Use the variant prop
<Button variant=“primary”>Save</Button>

The variant carries the meaning. The colour, padding, and motion follow from tokens. Light mode, dark mode, and reduced motion all just work.

Don't · Reach past the variant
<Button style={{ background: ‘#06A0A9’ }}>Save</Button>

Inline values bypass the token layer. Dark mode breaks. Brand updates skip you. The component’s contrast guarantees no longer apply.

API contract

Every component speaks the same prop language. If you’ve used one, the next one looks familiar. The shape:

interface ComponentProps {
  variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  as?: 'button' | 'a' | 'span';
  loading?: boolean;
  disabled?: boolean;
  iconLeft?: IconName;
  iconRight?: IconName;
  'aria-label'?: string;
  children?: ReactNode;
}

What each prop does, and why it’s the same shape every time.

Props every component shares
variant
Discrete style intent

Primary, secondary, ghost, danger – never a colour. The variant carries meaning; the colour token follows.

variant=“primary”
size
sm | md | lg

Three sizes, no more. md is the default. Density is set by the size, not by ad-hoc padding props.

size=“md”
as
Render-as override

Render as a button, an anchor, or a span. The component keeps its visuals; the host element keeps its semantics.

as=“a”
loading
Boolean

Replaces the visible label with a spinner and locks the control. Announces 'busy' to screen readers.

loading={isSaving}
disabled
Boolean

Visual + aria-disabled. Never silently swallows clicks – it announces itself first.

disabled
iconLeft / iconRight
Icon name

Icon name from the iconography set. The component handles spacing, colour, and alignment so you don't.

iconLeft=“arrow-right”
aria-label
String – required for icon-only

When the visible label is absent (icon button, close button), aria-label is required. The build fails without it.

aria-label=“Close”

What the API deliberately does not expose: colour and spacing. Those live in tokens, not props. If you want a different colour, change the variant. If you want different spacing, change the size. If neither fits, the component is wrong for the job – or the system needs a new variant. Either is a conversation, not a one-off override.

Out of scope

The system will not provide the items below. They’re useful, sometimes essential – but they belong to libraries that already do them better than we could.

Things we won't build
Drag-and-drop
Use a third-party lib

dnd-kit, Framer Motion's reorder, or react-aria's drag primitives. Theme them with our tokens; we don't reinvent the interaction model.

Recommendation: dnd-kit
WYSIWYG editor
Use a third-party lib

TipTap, Lexical, or ProseMirror. We ship type tokens and toolbar primitives; the editor engine isn't ours.

Recommendation: TipTap
Calendar / date picker
Planned, not yet

On the long-term roadmap, but not before forms 1.0 ships. Until then, native <input type='date'> is acceptable.

Native input until further notice
Charts as JSX
Use a chart lib

We ship the colour tokens for chart libraries to consume. The library itself is your call. See /design/dataviz/ for the palette.

Animation library
CSS + motion tokens

No Framer Motion or GSAP wrappers. Components use CSS transitions bound to motion tokens. Anything more elaborate is page-level work.

Tokens, not a runtime

Roadmap

The next twelve months. Phases ship together – we’d rather release “forms” than “text field” – and the dates are targets, not promises.

  • Q3 2026 Forms v1.0 Text, textarea, select, checkbox, radio, switch. The full set lands together.
  • Q3 2026 Card · Tag · Badge The display primitives forms depends on for layout.
  • Q4 2026 Top nav · Footer · Tabs Site-level chrome. Replaces the current ad-hoc nav across product surfaces.
  • Q4 2026 Modal · Toast · Banner Overlay and feedback patterns. Modal first because every form needs it.
  • Q1 2027 Table · Pagination · Empty state Tabular data and the empty case it falls back to.
  • Q1 2027 Tooltip · Popover · Menu The smaller overlays. Tooltip and popover share the same anchor primitive.

How to propose a component

Three things we want to see before work starts. Bring them to design review – it runs every other Wednesday at 14:00.

01

The use case

Where does it appear? What problem does it solve that an existing component doesn’t? One paragraph. Specifics beat abstractions every time.

02

Two reference designs

From inside the product if possible, from elsewhere if not. They tell us what “good” looks like before anyone opens Figma.

03

The dependency list

What tokens, what other components, what libraries. If something’s missing from the system, we’ll need to build that first.

Governance details – review cadence, who signs off, how breaking changes are versioned – live on the governance page.

Owners

Each category has a current owner. They review proposals, sign off on shipped releases, and take the on-call pager when something breaks. For anything cross-cutting, mail design@executivesupport.com.

CategoryLeadContact
NavigationTom Ellerydesign@executivesupport.com
FeedbackPriya Shahdesign@executivesupport.com
EditorialPriya Shahdesign@executivesupport.com