DESIGN
Primer Design System
Overview
Primer is GitHub's design system. It powers github.com and all GitHub products. The visual language is functional and neutral — it prioritizes clarity, information density, and accessibility over expressive aesthetics. The system supports nine themes (light, dark, high contrast, colorblind, dimmed) through a semantic all-functional token model.
When to use Primer as a reference:
- Productivity and developer tools with a GitHub-adjacent context
- Systems requiring multi-theme support without algorithmic color generation
- Interfaces where token names should describe UI intent, not visual appearance
Color
Token model
Three tiers: Base → Functional → Component/pattern. Components consume functional tokens only. Never use base tokens directly.
Functional token naming pattern:
{property}-{role}— e.g.bgColor-default,fgColor-muted{property}-{semantic}-{variant}— e.g.bgColor-success-emphasis,borderColor-danger-muted
Neutral tokens
/* Text / Foreground */
--fgColor-default /* primary text */
--fgColor-muted /* secondary text, metadata */
--fgColor-onEmphasis /* text on emphasis backgrounds */
--fgColor-disabled /* disabled state */
--fgColor-link /* interactive links */
/* Background */
--bgColor-default /* page background */
--bgColor-muted /* secondary bg — code blocks, sidebars, table headers */
--bgColor-inset /* recessed bg — inputs, wells */
--bgColor-emphasis /* high-emphasis bg — tooltips; pair with fgColor-onEmphasis */
--bgColor-inverse /* opposite-theme bg */
/* Border */
--borderColor-default /* standard borders */
--borderColor-muted /* subtle dividers */
--borderColor-emphasis /* strong borders */
Semantic color roles
/* accent — links, focus, selected */
--fgColor-accent
--bgColor-accent-muted
--bgColor-accent-emphasis
/* success — primary actions, positive states */
--fgColor-success
--bgColor-success-muted
--bgColor-success-emphasis
/* attention — warnings, active processes */
--fgColor-attention
--bgColor-attention-muted
--bgColor-attention-emphasis
/* danger — errors, destructive actions */
--fgColor-danger
--bgColor-danger-muted
--bgColor-danger-emphasis
/* open / closed / done — GitHub workflow states */
--fgColor-open
--fgColor-closed
--fgColor-done
--bgColor-open-emphasis
--bgColor-closed-emphasis
--bgColor-done-emphasis
/* sponsors — GitHub Sponsors context */
--fgColor-sponsors
--bgColor-sponsors-emphasis
Key rules
- Always use
fgColor-onEmphasisfor text on anybgColor-*.emphasisbackground. - Semantic role tokens auto-adapt across all nine themes.
bgColor-success-emphasisis the primary button background (green).bgColor-danger-emphasisis the danger button background (red).
Typography
Font stacks
--fontStack-system: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
--fontStack-monospace: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
No custom typeface. System fonts only.
Type scale
/* Base sizes */
--base-text-size-xs: 0.75rem; /* 12px — captions, compact labels */
--base-text-size-sm: 0.875rem; /* 14px — default body, most UI */
--base-text-size-md: 1rem; /* 16px — large body, small titles */
--base-text-size-lg: 1.25rem; /* 20px — medium titles */
--base-text-size-xl: 2rem; /* 32px — large headings */
--base-text-size-2xl: 2.5rem; /* 40px — display / hero */
Font weights
--base-text-weight-light: 300;
--base-text-weight-normal: 400; /* body text default */
--base-text-weight-medium: 500; /* labels, metadata emphasis */
--base-text-weight-semibold: 600; /* headings, strong labels */
Typographic styles (shorthand)
| Style | Size | Weight | Use |
|---|---|---|---|
| Display | 2.5rem | Semibold | Hero text |
| Title Large | 2rem | Semibold | Page headings |
| Title Medium | 1.25rem | Semibold | Section headings |
| Title Small | 1rem | Semibold | Sub-sections, card titles |
| Body Large | 1rem | Normal | Introductory prose |
| Body Medium | 0.875rem | Normal | Default UI text |
| Body Small | 0.75rem | Normal | Helper text, compact contexts |
| Caption | 0.75rem | Normal | Image captions, auxiliary labels |
| Code Block | 0.875rem | Normal | Multi-line code, monospace |
Rules
remunits throughout — supports browser zoom.- Line heights are unitless, aligned to 4px grid.
- Do not adjust
letter-spacing. - Use weight CSS variables, not raw numbers.
- Do not reorder heading tags (h1–h6) for visual styling — use CSS classes.
Spacing
Primer uses a 4px base grid. Most layout spacing is expressed in multiples of 4px.
--base-size-4: 0.25rem; /* 4px */
--base-size-8: 0.5rem; /* 8px */
--base-size-12: 0.75rem; /* 12px */
--base-size-16: 1rem; /* 16px */
--base-size-24: 1.5rem; /* 24px */
--base-size-32: 2rem; /* 32px */
--base-size-40: 2.5rem; /* 40px */
--base-size-48: 3rem; /* 48px */
--base-size-64: 4rem; /* 64px */
Shape
Primer uses a small set of border-radius values. Components tend toward subtle rounding.
--borderRadius-small: 3px; /* inline elements, small tags */
--borderRadius-medium: 6px; /* buttons, inputs, cards */
--borderRadius-large: 12px; /* larger containers */
--borderRadius-full: 9999px; /* pills, circular avatars */
Shadow / Elevation
--shadow-resting-xsmall /* cards, resting surfaces */
--shadow-resting-small /* slightly elevated surfaces */
--shadow-floating-small /* tooltips, small dropdowns */
--shadow-floating-medium /* menus, popovers */
--shadow-floating-large /* dialogs */
--shadow-inset /* active inputs, sunken elements */
Focus
All interactive elements must have a visible focus indicator.
--focus-outlineColor /* accent color in all themes */
--focus-outlineWidth /* 2px */
--focus-outlineOffset /* 2px */
box-shadow: 0 0 0 var(--focus-outlineWidth) var(--focus-outlineColor) is the standard focus ring implementation.
Interactive states
State layers use the bgColor-neutral-muted token at varying opacities, or theme-specific state tokens.
/* Component state tokens */
--control-bgColor-hover /* hover state background for controls */
--control-bgColor-active /* active/pressed state */
--control-bgColor-disabled /* disabled state background */
--control-borderColor-default
--control-borderColor-hover
--control-borderColor-danger
--control-fgColor-placeholder
Components
Button
Variants: Primary (success-emphasis), Secondary (default neutral), Danger (danger-emphasis), Invisible (transparent), Inactive, Loading.
bgColor-success-emphasis → Primary button bg
bgColor-danger-emphasis → Danger button bg
bgColor-default → Secondary button bg
fgColor-onEmphasis → Text on Primary and Danger buttons
focus-outlineColor → Focus ring
borderRadius-medium → Button shape
- One Primary button per page/group.
- Label should be descriptive enough without surrounding context.
- Prefer Inactive over Disabled — disabled buttons aren't always focusable.
- Loading state:
aria-disabled="true", keep focusable, use live region.
Form controls
control-bgColor-default → Input background
control-borderColor-default → Input border at rest
control-borderColor-hover → Input border on hover
borderColor-accent-emphasis → Focus border
borderColor-danger-emphasis → Error border
fgColor-danger → Error message text
control-fgColor-placeholder → Placeholder text
Status indicators (Labels, Badges)
Use semantic role token pairs:
- Muted:
bgColor-{role}-muted+fgColor-{role} - Emphasis:
bgColor-{role}-emphasis+fgColor-onEmphasis
GitHub workflow states use open, closed, done roles specifically.