Resources
Contribution
The system grows from product work. The process exists to make sure that what gets added is genuinely shared — and that adding it does not quietly cost every other team something.
Before proposing anythingPermalink to this section
Three questions that resolve most requests without a proposal at all.
Does an existing component already do this?
Search the component list and the patterns. A surprising number of requests are for something that exists under a different name — or for a composition of two things that already exist.
Is this needed by more than one surface?
A component with one consumer belongs in that consumer's codebase. Bring it to the system when a second team needs it — that is when the shared cost starts paying for itself.
Is this a variant, or a new component?
If it shares behaviour and semantics with something that exists and differs only in appearance, it is a variant. New components are for new behaviour.
Kinds of changePermalink to this section
Each requires a different amount of process, in proportion to how hard it is to reverse.
| Change | Process | Reviewers |
|---|---|---|
| Bug fix | Pull request | One systems maintainer |
| Documentation | Pull request | One systems maintainer |
| New variant on an existing component | Short proposal, then a pull request | One designer, one maintainer |
| New component | Full proposal, then a pull request | Two designers, two maintainers |
| New token | Full proposal | Two designers, two maintainers |
| Token value change | Full proposal — it affects every consumer | Two designers, two maintainers |
| Deprecation or removal | Full proposal, with a migration path | Two designers, two maintainers |
Writing a proposalPermalink to this section
Short and concrete. A proposal that cannot name its second consumer is usually a product component in disguise.
# Proposal: Combobox
## Problem
Three surfaces need a select that also accepts free text —
region assignment, label picking, and the member invite field.
All three currently use Input with a custom dropdown, and all
three implement keyboard navigation differently.
## Who needs it
- Deployments team — region assignment (shipping Q3)
- Content team — label picker (shipping Q3)
- Platform team — member invite (already built, would migrate)
## Why existing components do not cover it
Select holds a fixed list and cannot accept typed values.
Input has no list. Dropdown Menu runs commands, not values.
## Proposed API
<Combobox
value={value}
onValueChange={setValue}
allowCustomValue
options={regions}
/>
## Accessibility
Follows the ARIA combobox pattern: role="combobox" on the
input, aria-expanded, aria-activedescendant for the highlighted
option, and Escape to close without committing.
## Alternatives considered
- Extending Select with a filter field. Rejected: Select's
value semantics do not allow a value outside the list.
- Leaving it to each team. Rejected: three inconsistent
keyboard implementations is the problem we are solving.
## Cost
New component. Estimated 3 days including documentation.
Adds no new dependency — built on the existing Popover
primitive.What a component needs before it shipsPermalink to this section
This list is the definition of done. A component missing any of it is not ready, regardless of how well it works.
- An accepted proposal, with at least two named consumers.
- Implementation using semantic or component tokens only — no hardcoded values.
- Variants declared with class-variance-authority, so they can be overridden through className.
- Every applicable state: default, hover, pressed, focus visible, disabled, loading, error, selected and read-only.
- Keyboard support matching the relevant ARIA pattern, verified by hand.
- An accessible name for every interactive element, enforced by the type signature where possible.
- Contrast checked against every surface the component appears on.
- Reduced-motion behaviour that removes movement rather than shortening it.
- Responsive behaviour designed for narrow viewports, not inherited from the desktop layout.
- A documentation page with all four tabs, including do and don't examples.
- A live preview built from the production component, never a visual reproduction.
- A changelog entry naming the component and any tokens it introduces.
Code conventionsPermalink to this section
The patterns every component in the system follows. Matching them is what makes the codebase readable as one thing.
"use client";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/cn";
// 1. Variants declared with cva, base classes first.
const exampleVariants = cva(
["inline-flex items-center rounded-md", "transition-colors"],
{
variants: {
variant: { primary: "...", secondary: "..." },
size: { sm: "...", md: "..." },
},
defaultVariants: { variant: "primary", size: "md" },
},
);
// 2. Props extend the native element and the variant props.
export interface ExampleProps
extends React.ComponentProps<"div">,
VariantProps<typeof exampleVariants> {}
// 3. className is always accepted and merged last, so a
// caller can override any variant class.
export function Example({ className, variant, size, ...props }: ExampleProps) {
return (
<div
className={cn(exampleVariants({ variant, size }), className)}
{...props}
/>
);
}ReviewPermalink to this section
What reviewers actually check, in the order they check it.
- Does this belong in the system at all, or is it product-specific?
- Is it a variant of something that already exists?
- Does it use tokens, or has a value been hardcoded?
- Is every state implemented, or only the default?
- Does the keyboard path work without a mouse?
- Does every interactive element have an accessible name?
- Is the narrow-viewport behaviour designed, or merely allowed to happen?
- Does the documentation explain when not to use it?
Saying no is part of the job
A design system stays useful by staying small. Declining a component is not a rejection of the work — it is a judgement that the cost of everyone carrying it exceeds the benefit to the one team asking. Proposals are declined with a reason and, where possible, a suggested alternative.