# DESIGN.md · GitHub Primer (DS-004)

> Written for AI coding agents. Values marked **OFFICIAL** come from the documented source named below; values marked **ESTIMATED** were measured by us from our own screenshots and are approximate. Never treat ESTIMATED values as official brand tokens.

## Overview
- Type: Design System · Category: C. Design Systems
- Platforms: Web, React, Rails (ViewComponent), Figma
- Color theme: Monochrome light · Layout pattern: Documentation · Mood: Pragmatic, dense, developer-first
- License / terms: MIT (Primer code and primitives, © GitHub Inc.); Mona Sans SIL OFL 1.1; Octicons MIT; GitHub names and logos are trademarks
- Industry: Platform design system
- Patterns: Docs sidebar, Live component demo

GitHub’s design system: functional colour tokens (bgColor-*, fgColor-*, borderColor-*) that switch across light, dark and seven more themes, Mona Sans type roles, 28/32/40 px controls with a 44 px coarse-pointer target, 3/6/12 px radii, viewport ranges and documented UI patterns (empty states, forms, loading, saving) for React and Rails.

### Analysis (ours)
Primer is the system behind github.com: a dense, information-heavy product that developers read all day in light or dark mode. Its strongest idea is the three-tier token model. Base tokens (color-scale-pink-5) are never used directly; functional tokens (bgColor-default, fgColor-muted, borderColor-default) describe a role and change automatically across light, dark, dimmed, high-contrast and colour-blind themes; component tokens are kept to a minimum. Type is set in Mona Sans with system fallbacks, with 14 px body-medium as the default UI text and roles from 12 px caption to 40 px display. Controls are 28, 32 and 40 px high, with a 44 px minimum target on coarse pointers and 16 px on fine ones. Layout uses viewport ranges (narrow under 768 px with one column, regular up to two, wide from 1400 px up to three) instead of a strict grid. Primer also documents UI patterns (empty states, forms, loading, saving, progressive disclosure) as well as components, which is what makes it worth studying. Lessons: one primary button per group, write functional token names, and design every multi-column page for the case where the columns no longer fit.

### Best practices (ours)
- Use functional tokens (bgColor-default, fgColor-muted, borderColor-default) in code; base scale tokens don’t respect colour modes and should never be used directly.
- Ship light and dark from day one and test the high-contrast theme, where Primer aims for 7:1 for most text.
- Keep 14 px body-medium as the default UI size and use title-medium (20 px) as the default page title.
- Use one primary button per group and rarely more than one per page; danger buttons should usually open a confirmation.
- Size controls at 28/32/40 px and keep touch targets at least 44 px on coarse pointers.
- Design multi-column pages for the narrow range (<768 px, one column) first, then add columns at regular (≥768 px) and wide (≥1400 px).
- Follow the documented UI patterns (empty states, loading, saving, forms) rather than inventing per-feature behaviour.

### Deep analysis
Values marked OFFICIAL come from the cited official docs page or the official npm token package installed 2026-10-25 (UTC+8) (@carbon/themes 11.78.0, @carbon/type 11.70.0, @carbon/layout 11.62.0, @carbon/motion 11.55.0, @primer/primitives 11.10.0, @fluentui/react-theme 9.2.2). ESTIMATED values were computed or observed by us that day (WCAG 2 contrast ratios, what our captures show). OURS is our interpretation.

#### Purpose and audience (OFFICIAL) · source: https://primer.style/
- Primer is GitHub’s design system, split into Product UI, Brand UI, Octicons, Primitives (“design tokens for color, spacing, and typography”), Accessibility and a Brand Toolkit.
- Audience: engineers and designers building github.com and GitHub-adjacent tools; code is MIT on GitHub.
- Implementations: Primer React, Primer ViewComponents (Rails) and CSS; a Figma library offers components and tokens in light and dark modes.

#### Colour model (OFFICIAL) · source: https://primer.style/product/getting-started/foundations/color-usage/
- “GitHub’s UI offers two color modes, light and dark. Primer supports both color modes across nine themes.”
- Three token tiers: base (map to raw values, never used directly, don’t respect colour modes), functional (text, borders, shadows, backgrounds; respect modes; most used) and component/pattern (limited; functional preferred).
- Neutral scales run 0–13 and are inverted between light and dark so both themes can share functional tokens.
- High-contrast themes use neutral steps 2–7 for backgrounds, 10 for borders and 11–13 for text, targeting at least 7:1 for most text and interactive elements.

#### Typography and layout (OFFICIAL) · source: https://primer.style/product/getting-started/foundations/typography/
- Mona Sans VF with system fallbacks; body-medium 14 px is the “Default UI font”; title-medium 20 px is the “Default page title”, whose 32 px-equivalent line height matches medium control heights.
- caption (12 px, tight) “doesn’t pass accessibility requirements” for multi-line text.
- Layout uses viewport ranges: narrow <768 px (1 column), regular ≥768 px (up to 2), wide ≥1400 px (up to 3); breakpoints are “a unit in a ruler”, not mobile-first rules.
- Layout principles: strive for a focused experience; design fully functional responsive experiences; stay consistent inside and outside GitHub.

#### Components and states (OFFICIAL) · source: https://primer.style/product/components/button/
- Button variants: Primary (“Highest-priority action; use sparingly. Never put more than one in a group of buttons, and rarely use more than one per page”), Default, Invisible and Danger (“typically prompt a confirmation dialog”).
- Sizes small, medium (default) and large (“use sparingly”), mapping to 28/32/40 px control heights; leading and trailing visuals (e.g. counters), loading (spinner) and inactive states are documented.
- Primary rest colour is bgColor-success-emphasis (#1f883d light, #238636 dark), hover #1c8139 / #29903b; focus is a 2 px outline in #0969da / #1f6feb.
- UI patterns are documented alongside components: empty states, feature onboarding, forms, loading, navigation, saving, progressive disclosure and more.

#### Contrast checks we ran (ESTIMATED) · source: https://primer.style/product/primitives/color/
- fgColor-default on bgColor-default: light 15.8:1, dark 17.39:1.
- fgColor-muted on bgColor-default: light 6.11:1, dark 6.5:1.
- White on the primary button (#1f883d): 4.52:1; on the dark-mode primary (#238636): 4.63:1.
- fgColor-accent links on white: 5.19:1.

#### Documentation site UX (OURS) · source: https://primer.style/
- Product UI docs pair a left navigation (Getting started, Foundations, UI patterns, Components) with live React examples, a StackBlitz link and a ‘Show full code’ toggle on each.
- Each component page links React, Rails and Figma sources with a status badge (e.g. ‘React ready’), which tells you quickly what is production-safe.
- A dark-mode switch on the docs lets you check every example in both modes.

#### Lessons to take (OURS) · source: https://primer.style/
- Keep a strict three-tier token model and ban base tokens in product code.
- Document patterns (empty, loading, saving) as well as components; that’s where consistency usually breaks.
- Tie type line heights to control heights so text and controls align without manual nudging.
- Plan narrow, regular and wide layouts instead of tuning for each breakpoint.

### Usage terms at a glance (our summary, not legal advice)
- Commercial use: Yes. Primer code and primitives are MIT; Mona Sans is OFL 1.1
- Attribution: Keep the MIT copyright notice in shipped code. GitHub names and logos are trademarks, so don’t present your product as GitHub’s
- Redistribution: Code yes (MIT); font yes (OFL); GitHub marks no
- How you get it: npm (@primer/react, @primer/primitives, @primer/octicons), Ruby gem (primer_view_components), Figma

## Color tokens
OFFICIAL · Functional colour tokens (light / dark). OFFICIAL values from @primer/primitives 11.10.0 (MIT, © GitHub Inc.) functional theme files light.css and dark.css, as documented on primer.style (Color usage and color primitives pages). Use the CSS variable names directly, e.g. var(--bgColor-default).

| Role | Light | Dark |
|---|---|---|
| bgColor-default · Page and default surface | `#ffffff` | `#0d1117` |
| bgColor-muted · Secondary surfaces, sidebars | `#f6f8fa` | `#151b23` |
| bgColor-emphasis · Strong neutral (e.g. tooltips, emphasis labels) | `#25292e` | `#3d444d` |
| bgColor-accent-emphasis · Accent fill (selected, primary info) | `#0969da` | `#1f6feb` |
| bgColor-accent-muted · Accent tint | `#ddf4ff` | `#388bfd1a` |
| bgColor-success-emphasis · Success fill; primary button rest | `#1f883d` | `#238636` |
| bgColor-danger-emphasis · Danger fill | `#cf222e` | `#da3633` |
| bgColor-attention-emphasis · Attention / warning fill | `#9a6700` | `#9e6a03` |
| bgColor-done-emphasis · Done (merged/closed-complete) fill | `#8250df` | `#8957e5` |
| fgColor-default · Primary text | `#1f2328` | `#f0f6fc` |
| fgColor-muted · Secondary text | `#59636e` | `#9198a1` |
| fgColor-onEmphasis · Text on emphasis fills | `#ffffff` | `#ffffff` |
| fgColor-accent · Links, accent text | `#0969da` | `#4493f8` |
| fgColor-success · Success text | `#1a7f37` | `#3fb950` |
| fgColor-danger · Danger text | `#d1242f` | `#f85149` |
| fgColor-attention · Attention text | `#9a6700` | `#d29922` |
| fgColor-done · Done text | `#8250df` | `#ab7df8` |
| borderColor-default · Default borders | `#d1d9e0` | `#3d444d` |
| borderColor-accent-emphasis · Focus outline colour (focus-outlineColor) | `#0969da` | `#1f6feb` |
| button-primary-bgColor-hover · Primary button hover | `#1c8139` | `#29903b` |

ESTIMATED · dominant colors measured from our screenshot(s) of the source site (median-cut quantization; share = % of pixels). Approximate, not official:

- `#FFFFFF` ~62%
- `#8699B1` ~5%
- `#D6E7E7` ~4%

## Typography
OFFICIAL · Primer functional type roles (Mona Sans VF, then -apple-system, Segoe UI, Noto Sans…; monospace ui-monospace, SFMono-Regular…)

| Role | Weight | Size | Line height | Tracking |
|---|---|---|---|---|
| display | Medium | 40 px (2xl) | 1.375 (snug) | — |
| title-large | Semibold | 32 px (xl) | 1.5 (normal) | — |
| title-medium | Semibold | 20 px (lg) | 1.625 (relaxed) | — |
| title-small | Semibold | 16 px (md) | 1.5 (normal) | — |
| subtitle | Regular | 20 px (lg) | 1.625 (relaxed) | — |
| body-large | Regular | 16 px (md) | 1.5 | — |
| body-medium (default UI text) | Regular | 14 px (sm) | 1.5 | — |
| body-small | Regular | 12 px (xs) | 1.625 | — |
| caption | Regular | 12 px (xs) | 1.25 (tight) | — |
| codeBlock (monospace) | Regular | 13 px (0.8125rem) | 1.5 | — |

## Spacing, radii, shadows
- OFFICIAL · Base size scale: 2 · 4 · 6 · 8 · 12 · 16 · 20 · 24 · 28 · 32 · 36 · 40 · 44 · 48 · 64 · 80 · 96 · 112 · 128 px (--base-size-*)
- OFFICIAL · Control heights: small 28 · medium 32 · large 40 px; minimum target 44 px (coarse pointer) / 16 px (fine)
- OFFICIAL · Border radius: small 3 · medium 6 (default) · large 12 px · full (pill)
- OFFICIAL · Stack gap / padding: condensed 8 · normal 16 · spacious 24 px
- OFFICIAL · Breakpoints: xsmall 320 · small 544 · medium 768 · large 1012 · xlarge 1280 · xxlarge 1400 px
- OFFICIAL · Viewport ranges: narrow <768 px (1 column) · regular ≥768 px (up to 2) · wide ≥1400 px (up to 3)
- OFFICIAL · Focus: 2 px outline (--focus-outline-width) in focus-outlineColor (#0969da light / #1f6feb dark)
- OFFICIAL · Shadows (light): resting-small 0 1px 1px #1f23280a, 0 1px 2px #1f232808 · floating-small 0 0 0 1px #d1d9e040, 0 6px 12px -3px #25292e0a, 0 6px 18px #25292e1f
- OFFICIAL · Motion (base): durations 0–1000 ms in 50/100 ms steps; easings ease (0.25,0.1,0.25,1), easeIn (0.7,0.1,0.75,0.9), easeOut (0.3,0.8,0.6,1), easeInOut (0.6,0,0.2,1)
- Gaps (not documented / not verified): Primer has no fixed column grid; it uses viewport ranges and PageLayout. Letter-spacing is not tokenised (tracking column shows —).

## Components
- Button (primary, default, invisible, danger; small/medium/large)
- IconButton
- ActionList, ActionMenu
- Autocomplete
- Avatar, AvatarStack
- Banner, Flash
- Blankslate (empty state)
- Breadcrumbs
- Checkbox, Radio, ToggleSwitch
- Dialog
- FormControl, TextInput, Textarea, Select
- Label, StateLabel, CounterLabel
- NavList, UnderlineNav
- PageHeader, PageLayout, SplitPageLayout
- Pagination
- ProgressBar, Spinner, SkeletonText
- SegmentedControl
- Timeline
- Tooltip
- TreeView
- DataTable

## Layout rules
- Observed layout pattern: **Documentation** (from our captures).

## Usage
```
npm install @primer/react @primer/primitives
import '@primer/primitives/dist/css/functional/themes/light.css'
import '@primer/primitives/dist/css/functional/size/size.css'
<ThemeProvider colorMode="auto"><BaseStyles>
  <Button variant="primary">Create repository</Button>
</BaseStyles></ThemeProvider>
```

## Do’s and don’ts
- Do: Keep chrome neutral and let content (images, icons, type) carry color.
- Don’t: Don’t introduce decorative color that competes with content.
- Do: follow the source’s license/terms listed above.
- Don’t: present ESTIMATED colors as official tokens.

## Related entries (ours)
- DS-003: Carbon is the enterprise alternative; compare its four themes with Primer’s functional tokens. · https://design-library-byt.pages.dev/entry/DS-003
- WR-003: Vercel’s site shows a similar developer-first neutral palette on a marketing page. · https://design-library-byt.pages.dev/entry/WR-003
- IC-002: Heroicons fills the same role as Octicons when you are not on GitHub’s stack. · https://design-library-byt.pages.dev/entry/IC-002
- DS-005: Fluent’s alias tokens are the closest naming model to Primer’s functional tokens. · https://design-library-byt.pages.dev/entry/DS-005

## Sources
- https://primer.style/
- Library entry: https://design-library-byt.pages.dev/entry/DS-004
