OCBridge · Design Engineering

Building a Design System for an AI Hiring Copilot

Tested product decisions, shared across Figma, React, Storybook, and release.

Kelly PengAugust 20264 min read
12Foundations
19Components
13Product patterns
6Workflow contracts

Code-derived inventory documented across five product screens.

OCBridge React design system showing semantic color foundations and component controls
OCBridge Design System · foundations, React components, executable docs.

This was an AI recruiting product, not a component gallery. Evidence, confidence, and human approval had to stay the same in design and code.

The system grew out of a trust problem.

Ranked candidates arrived fast. Recruiters still could not explain why. Principle: AI does the work; the recruiter owns the call.

I systemized what survived real use.

I started from recruiter flows, not a button inventory. A pattern entered the library only after it survived testing, the API, and a real workflow.

01Validated flowA repeated product problem with evidence behind it.
02Shared patternAnatomy, states, and behavior defined in Figma.
03Executable contractTokens, typed React props, stories, and tests.

Meaning first, then style.

Blue is action. Purple is AI reasoning. Neutrals carry evidence and status. One icon language keeps dense recruiting screens scannable.

Visual rules became component contracts.

Figma was not a second set of screens. Repeated decisions became foundations, components, and patterns — one path from a visual rule to a typed React prop.

01

Audit the product. Keep what already survived recruiter workflows.

02

Bind foundations. Color, type, spacing, grid, elevation — via Auto Layout.

03

Expose the contract. Size, state, intent, loading, selection as named properties.

04

Return to the flow. Swap local UI for library instances and check they still hold.

Explore the Figma fileClick a stage
OCBridge organized Figma page groups OCBridge component selected state in Figma OCBridge visual design system foundations organized in Figma OCBridge Figma components applied to product states

Click a stage: file structure → components → product.

Next: orchestration on the project we already share.

Product, Design, and Frontend already work in one Git project. What’s missing is an agent that can read context, move between Figma and Web, and sync back.

Current · what exists todayOne project, cross-functional collaboration
PRODUCT / PDWrite PRD + spec
DESIGNER / UXDesign + spec
FRONTEND / DEVCoding
All contribute to one project
SHARED PROJECTGit repositoryHTML · JSX · JSON
Next improvement · add an AI-native collaboration layer
Future · additive improvementAgent orchestration around the same source
Agent synchronizes back into the shared project
PRD / requirementsMeeting minutesUser feedback
GENERAL AGENTAI design toolkitOCBridge system context
FigmaWeb
DESIGNHuman direction remains explicit

This layer does not replace the current workflow. It reads the same evidence and returns changes to the source Product, Design, and Frontend already own.

Today’s OCBridge workflow, then the agent layer I would add.

Every semantic token traces back to a product decision.

Shared names were not enough. Blue is a human action; purple is the AI’s voice. Those roles went from research → Figma variables → --oc-* CSS used by React.

01 · EVIDENCERecruiter + API findingsConfidence, explainability, and ownership constraints.
02 · PRINCIPLEVisible and ownedAI reasoning stays distinct; people retain the final action.
03 · SEMANTIC TOKENRole, not raw valueattention, primary, and confidence tiers.
04 · CONSUMERComponent + patternAIBlock, Button, Feedback, and Candidate Review.
OCBridge semantic color variables organized into background, text, and brand roles in Figma
Figma: colors by role and light/dark, before components consume them.
--oc-color-primaryHuman actions and deliberate approval moments.
--oc-color-attentionAI-generated reasoning that requires review.
success / warning / dangerConfidence-dependent outcomes and feedback.

Figma records the architecture. The CSS token file is the source of truth for shipped names.

01

Name by role, never by value. --oc-color-attention means AI reasoning. Purple can change without renaming anything.

02

Scale by decision. Radius is field, row, card, surface, or pill — a role, not a number.

03

Theme by attribute. data-oc-theme flips dark mode without touching a component.

04

Tokenize the invariants. Focus ring and motion are tokens too, so a11y is not re-decided per component.

:root, [data-oc-theme='light'] {
  --oc-color-primary: #1a6ee8;    /* interaction */
  --oc-color-attention: #9170ff;  /* AI reasoning */
  --oc-radius-card: 10px;
  --oc-focus-ring: 0 0 0 2px var(--oc-color-surface-raised),
                   0 0 0 4px var(--oc-color-primary);
}

[data-oc-theme='dark'] {
  --oc-color-primary: #85b7ff;    /* the name holds, only the value moves */
  --oc-color-attention: #bca9ff;
}

Visual decisions became typed behavior.

Figma can show a loading button. It cannot stop a double submit or tie an error to a field. In React, each visual decision became a prop, a behavior, and a test.

Candidate Review selected, qualified, and disqualified states in Figma
Figma · Candidate Review states in the product flow.
OCBridge component documentation and typed controls in Storybook
Storybook · props, states, and responsive behavior.
Figma stateReact APIStorybookQA evidence
Selected candidateselectedSelectedVisual baseline
Candidate contentcandidateLongContentContent stress test
Decision controlsactionsWithPipelineContextKeyboard + axe
AI evidenceconfidence + sourceRendered metadataAccessible output
01 · CONTRACT

Typed props: variant, loading, disabled, removable, selected, tone.

02 · RENDER

Props become HTML semantics, visible states, focus, and the right ARIA.

03 · PROOF

Each state gets a story. Axe checks semantics; visual tests catch layout drift.

04 · RELEASE

It ships when API, story, a11y, and screenshot agree.

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary' | 'utility' | 'danger';
  loading?: boolean;
}

<Button loading={isSubmitting} disabled={!canApprove}>
  Approve candidate
</Button>

// Native disabled behavior + aria-busy + one tested visual state

The executable system is a real React library.

Handoff kept losing the contract — missing empty states, dropped focus rings, loading buttons that still submitted twice. I shipped the component: Figma anatomy as typed props, tokens, stories, and tests. The Action bar below is those primitives under one responsive contract.

OCBridge React Design System · Action bar pattern
Open full view ↗

The first Menu was two objects: click a pill, a popup appears. I rebuilt it as one surface with closed and open.

01 · ORIGINALTwo separate objectsA pill triggers a detached popup.
02 · CONNECTEDOne stable surfaceShared container; clipping stops text reflow.
03 · MOTIONReveal with directionOpacity, blur, and scale after the surface expands.

Order: relationship, then stability, then feel. Reduced motion skips the transition.

<motion.div
  className="min-w-0 overflow-hidden"
  animate={{ width: open ? 224 : 112, height: open ? 228 : 42 }}
>
  <div style={{ width: 222 }}>
    <PanelContent
      animate={{ opacity: 1, filter: 'blur(0)', scale: 1 }}
    />
  </div>
</motion.div>

Chip shape came from role, then four variants.

The pill means compact, removable metadata. Selection and removal stay independent booleans. Variants change what leads the label — not what the chip means.

01 · Outline
Design systems ×

Default skill. Border keeps it separate on white.

02 · Ghost
Design systems ×

Lower emphasis inside a bounded container.

03 · Icon
Design systems ×

Icon for category; text stays the accessible label.

04 · Avatar
Kyle Han ×

Identity leads when the chip is a person.

<Chip
  variant="avatar"
  selected
  removable
  onRemove={() => removeFilter(candidate.id)}
>
  Kyle Han
</Chip>

Storybook made the handoff executable.

Each doc pairs the real component with props, named states, and source — design and engineering review the same object. Button covers primary, secondary, danger, loading, disabled; the story is the fixture for a11y and visual tests.

OCBridge Storybook · Button documentation, controls, source, and accessibility
Open Storybook ↗

A library becomes infrastructure when change has a path.

Every push: component tests, Playwright diffs, a11y audits. Automation flags a snapshot or a missing name. A person still decides if the product principle held. Goal: coherent change, not perfect consistency.

Visual regression comparison and review log for OCBridge components
A visual change is evidence for review, not a silent regression.

A design system is becoming a decision system.

Figma components and one-off React stop being enough. The system has to keep why: valid states, visible evidence, when a human must approve. AI adds uncertainty, provenance, drafts, recovery — and tokens, typed APIs, and stories become machine-readable context, not just docs.

01 · INPUTStructure → intentGoals, rules, and constraints live in the system.
02 · EXPERIENCEStatic → generativeThe UI may change at runtime; semantics stay stable.
03 · QUALITYReview → evaluationHumans and evaluators test against the same contracts.

GenUI does not make design systems less relevant. It makes a system’s meaning more important than its pixels.