Skip to content

Latest commit

 

History

History
449 lines (332 loc) · 23.5 KB

File metadata and controls

449 lines (332 loc) · 23.5 KB

Vercel — Design Language Reference

1. Visual Theme & Atmosphere

Vercel's interface is minimalism elevated to an engineering principle. Every pixel serves a purpose, every absence of ornament is a deliberate choice. The visual language strips away the superfluous — no gradients, no decorative borders, no color for color's sake — leaving behind a monochromatic canvas where content and function occupy the entire foreground. The background is a near-white rgb(250, 250, 250), text is a near-black rgb(23, 23, 23), and between them sits a precisely calibrated grayscale that communicates hierarchy without ever raising its voice.

What makes Vercel's design language remarkable is its relentless restraint. Color appears only when it must: blue rgb(0, 114, 245) marks interactive elements and focus states, and nothing else. Status indicators — greens, ambers, reds, purples — exist in small dot-sized badges (div.size-2.5), never as background fills or large swaths. The result is an interface that feels engineered rather than designed, where every visual decision can be justified by a functional requirement. Shadows replace borders. Weight replaces size. Spacing replaces dividers.

The atmosphere is one of quiet confidence — the kind of UI that a developer trusts instinctively because it never tries to impress. It communicates through density of information and precision of layout, powered by 96 custom CSS properties that form one of the most comprehensive design token systems on the web.


2. Color Palette & Roles

Core Interface Colors

Role Value CSS Source Usage
Background (primary) rgb(250, 250, 250) / #FAFAFA body backgroundColor Page canvas, surface base
Background (elevated) rgb(255, 255, 255) / #FFFFFF card/link surfaces Cards, modals, elevated panels
Background (recessed) rgb(242, 242, 242) / #F2F2F2 switch control surface Toggle tracks, input backgrounds
Text (primary) rgb(23, 23, 23) / #171717 body color Headings, primary content
Text (secondary) rgb(77, 77, 77) / #4D4D4D button color Navigation items, secondary labels
Text (muted) rgb(143, 143, 143) / #8F8F8F grayLine surface Decorative lines, disabled states
Interactive accent rgb(0, 114, 245) / #0072F5 link color, focus ring Links, focus rings, active states
Focus ring (alt) rgb(0, 95, 204) / #005FCC input focus outline Native input focus indicators

Status & Category Indicators

These colors appear exclusively as small indicator dots (div.size-2.5 — approximately 10px) and never as large fills:

Color Value Hex
Blue rgb(0, 98, 209) #0062D1
Cyan rgb(82, 174, 255) #52AEFF
Teal (light) rgb(69, 222, 197) #45DEC5
Teal (dark) rgb(6, 122, 110) #067A6E
Green (dark) rgb(57, 142, 74) #398E4A
Green (medium) rgb(69, 165, 87) #45A557
Green (light) rgb(108, 218, 117) #6CDA75
Orange rgb(255, 153, 10) #FF990A
Red rgb(229, 72, 77) #E5484D
Pink rgb(234, 62, 131) #EA3E83
Purple (dark) rgb(120, 32, 188) #7820BC
Purple (light) rgb(191, 137, 236) #BF89EC

Design Token Mapping (CSS Custom Properties)

Token Value Role
--ds-shadow-background-border 0 0 0 1px var(--ds-background-200) Surface-aware border layer
--ds-shadow-border-base 0 0 0 1px #00000014 Universal border simulation
--ds-shadow-border var(--ds-shadow-border-base), var(--ds-shadow-background-border) Combined default border
--ds-focus-ring 0 0 0 2px var(--ds-background-100), 0 0 0 4px var(--ds-focus-color) Double-ring focus pattern
--ds-overlay-backdrop-color var(--ds-background-200) Modal/overlay backdrop
--ds-overlay-backdrop-opacity .8 Backdrop transparency
--geist-text-gradient linear-gradient(180deg, #000c 0%, #000 100%) Text gradient effect (marketing)
--header-border-bottom 0 1px 0 0 #0000001a Header separator shadow
--header-import-flow-background #fafafacc Semi-transparent overlay

Color Philosophy

Vercel is fundamentally achromatic. The interface operates within a 4-stop grayscale: #FAFAFA#F2F2F2#EBEBEB#171717. Blue (#0072F5) is the sole interactive accent — it appears in links, focus rings, and the skip-to-content indicator, and nowhere else. Every other color is confined to status indicator dots no larger than 10px, enforcing a strict hierarchy where chromatic information signals data, never decoration.


3. Typography Rules

The Geist Type System

Vercel uses its proprietary Geist font family — a typeface designed specifically for developer tooling interfaces. Two variants serve distinct purposes:

  • Geist Sans — all interface text (headings, body, navigation, buttons, labels)
  • Geist Mono — code blocks and monospaced content, with fallback to ui-monospace, SFMono-Regular, "Roboto Mono"

Both fonts enable OpenType ligatures via font-feature-settings: "liga".

Type Hierarchy

Element Size Weight Line Height Letter Spacing Role
h1 48px 600 48px (1.0) -2.28px Hero headlines
h3 32px 600 40px (1.25) -1.28px Section titles
h2 14px 500 20px (1.43) -0.28px Subsection labels
h5 14px 400 20px (1.43) normal Tertiary headings
body 16px 400 normal normal Base reading text
a 16px 400 normal normal Inline links
button 14px 400 14px (1.0) normal Button labels
label 14px 400 20px (1.43) normal Form labels
p 12px 400 16px (1.33) normal Small body text, captions
code 13px 500 20px (1.54) normal Code snippets (Geist Mono)
pre 13px 500 20px (1.54) normal Code blocks
input 13.3px 400 normal normal Form inputs

Weight Philosophy: The Three-Weight Rule

Vercel uses exactly three font weights — and deliberately excludes bold (700):

Weight Name Usage
400 Regular Body text, links, buttons, labels, form elements
500 Medium Code blocks, subsection headings (h2), UI emphasis
600 Semibold Display headings only (h1, h3)

There is no weight 700 anywhere in the system. This constraint is philosophical: Vercel considers semibold sufficient for emphasis, and true bold too heavy for a minimalist interface. Emphasis is communicated through size and spacing, not weight.

Aggressive Negative Letter-Spacing

Vercel's most distinctive typographic trait is extreme negative tracking on headlines:

  • h1 at 48px: -2.28px (approximately -4.75% of font size)
  • h3 at 32px: -1.28px (approximately -4% of font size)
  • h2 at 14px: -0.28px (-2% of font size)

This tightening creates a sense of density and precision at display sizes, reinforcing the engineered aesthetic. At body sizes (16px and below), letter-spacing returns to normal.

Form Typography Tokens

Token Value Usage
--geist-form-large-font 1rem (16px) Large form inputs
--geist-form-large-line-height 1.5rem (24px) Large form line height
--geist-form-font .875rem (14px) Default form inputs
--geist-form-line-height 1.25rem (20px) Default form line height
--geist-form-small-font .875rem (14px) Small form inputs
--geist-form-small-line-height .875rem (14px) Small form line height

4. Component Stylings

Button States (9 Interactive States Captured)

Vercel buttons follow a ghost-first pattern — default state is fully transparent, with hover and focus providing visual feedback:

Navigation Buttons (Products, Resources, Solutions)

State Background Text Color Box Shadow Outline
Default transparent rgb(77, 77, 77) none none
Hover rgb(235, 235, 235) rgb(23, 23, 23) none none
Focus ~transparent rgb(23, 23, 23) #FFF 0 0 0 2px, #0072F5 0 0 0 4px none

Key observations:

  • Hover fills with a subtle gray (#EBEBEB) and promotes text from secondary to primary color
  • Focus applies the signature double-ring pattern: a 2px white inner ring creates separation from the element, then a 4px blue outer ring provides the visible indicator
  • No transform, opacity, or transition changes — interactions are purely color-based

Links

Variant Default Color Focus Behavior
Standard link rgb(23, 23, 23) outline: rgb(0, 114, 245) auto 2px
Navigation link rgb(77, 77, 77) outline: rgb(0, 114, 245) auto 2px
Skip-to-content rgb(0, 114, 245) opacity: 0 -> 1, double-ring focus

Form Inputs

State Background Box Shadow Outline
Default transparent none none
Focus transparent none rgb(0, 95, 204) auto 1px

Note the focus blue for inputs (#005FCC) differs slightly from the button focus blue (#0072F5) — a darker shade for the thinner 1px outline ensures equivalent visual weight.

The Double-Ring Focus Pattern

Vercel's most distinctive interaction pattern, defined as --ds-focus-ring:

0 0 0 2px var(--ds-background-100),   /* White inner ring — gap */
0 0 0 4px var(--ds-focus-color)        /* Blue outer ring — indicator */

This creates a 2px white buffer between the element and the blue focus ring, ensuring the ring is visible against any background — including elements that are themselves blue.

Border Radius Scale

Value Usage
6px Default component radius (--geist-radius)
8px Marketing components (--geist-marketing-radius)
12px Cards, elevated panels
12px 12px 0px 0px Top-anchored panels (drawers, sheets)
50% / 100% Avatars, circular indicators
9999px / 64px / 100px Pill shapes (tags, badges, full-round buttons)

Form Size Tokens

Size Height Token Value
Small --geist-form-small-height var(--geist-space-small) = 32px
Default --geist-form-height var(--geist-space-medium) = 40px
Large --geist-form-large-height var(--geist-space-large) = 48px

5. Layout Principles

Spacing Scale (Geist Space System)

Vercel's spacing system uses a 4px base unit with multiplier naming:

Token Value Multiplier
--geist-space 4px 1x
--geist-space-2x 8px 2x
--geist-space-3x 12px 3x
--geist-space-4x 16px 4x
--geist-space-6x 24px 6x
--geist-space-8x 32px 8x
--geist-space-10x 40px 10x
--geist-space-16x 64px 16x
--geist-space-24x 96px 24x
--geist-space-32x 128px 32x
--geist-space-48x 192px 48x
--geist-space-64x 256px 64x

Note the scale is not linear — it jumps from 10x to 16x, skipping 12x and 14x. The usable range spans from 4px to 256px (a 64:1 ratio).

Semantic Spacing Aliases

Token Value Usage
--geist-space-small 32px Small component height, compact sections
--geist-space-medium 40px Default component height
--geist-space-large 48px Large component height, generous sections
--geist-space-gap 24px Default gap between elements
--geist-space-gap-half 12px Tight gap
--geist-space-gap-quarter 8px Minimal gap
--geist-gap-double 48px Double-width gap

Negative Space Tokens

Every spacing value has a corresponding negative token (e.g., --geist-space-4x-negative: -16px), enabling precise pull-back positioning for overlapping elements and negative margins — 15 negative tokens total.

Page Layout

Token Value Usage
--geist-page-width 1200px Standard content width
--ds-page-width 1400px Design system / wider content
--geist-page-margin 24px (= --geist-space-gap) Horizontal page padding
--geist-page-width-with-margin calc(1200px + 48px) Full width including margins
--header-height 64px Fixed header height
--header-sub-menu-height 46px Sub-navigation bar
--banner-min-height 64px Announcement banner

Observed Element Spacing

Element Padding Gap
main 0 16px
header 0 24px 32px
footer 40px 24px
section 0

6. Depth & Elevation

The Shadow-as-Border Technique

Vercel's most technically distinctive pattern: box-shadow replaces CSS border entirely. Instead of border: 1px solid, Vercel uses:

box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);

This 0px 0px 0px 1px shadow — zero offset, zero blur, 1px spread — creates a visually identical border without affecting box-model dimensions. Benefits:

  1. No layout shift — borders add to element dimensions (unless using box-sizing); shadows do not
  2. Composable — multiple shadow layers can be stacked in a single box-shadow declaration
  3. Smooth transitions — shadows animate more smoothly than border-color changes
  4. Layered borders — a single element can have multiple "border" rings at different offsets

Shadow Elevation Scale

Level Token Value Usage
Border only --ds-shadow-border 0 0 0 1px #00000014, 0 0 0 1px var(--ds-background-200) Default card/container boundary
Small --ds-shadow-border-small Border + 0px 2px 2px #0000000a Slightly raised elements
Medium --ds-shadow-border-medium Border + 0px 2px 2px #0000000a, 0px 8px 8px -8px #0000000a Cards, dropdowns
Large --ds-shadow-border-large Border + 0px 2px 2px #0000000a, 0px 8px 16px -4px #0000000a Popovers, floating panels
Tooltip --ds-shadow-tooltip Border + 0px 1px 1px #00000005, 0px 4px 8px #0000000a Tooltip containers
Menu --ds-shadow-menu Border + 0px 1px 1px #00000005, 0px 4px 8px -4px #0000000a, 0px 16px 24px -8px #0000000f Dropdown menus
Modal --ds-shadow-modal Border + 0px 1px 1px #00000005, 0px 8px 16px -4px #0000000a, 0px 24px 32px -8px #0000000f Modal dialogs
Fullscreen --ds-shadow-fullscreen Same as modal Fullscreen overlays

Shadow Composition Pattern

Every elevated shadow composes three layers:

  1. Border layer (--ds-shadow-border-base): 0 0 0 1px #00000014 — the universal 1px "border"
  2. Depth layer: Actual drop shadow with increasing blur/offset per elevation
  3. Background border (--ds-shadow-background-border): 0 0 0 1px var(--ds-background-200) — surface-aware ring

Observed Shadow Values (From Live Elements)

Shadow Semantic Role
rgb(235, 235, 235) 0px 0px 0px 1px Light border ring (hover state, #EBEBEB)
rgba(0, 0, 0, 0.08) 0px 0px 0px 1px Standard border simulation
rgba(0, 0, 0, 0.04) 0px 2px 2px 0px Micro-elevation (subtle lift)
rgb(255, 255, 255) 0px 0px 0px 2px, rgb(0, 114, 245) 0px 0px 0px 4px Focus double-ring
Complex 3-layer composite Card with border + small shadow + background ring
Complex 5-layer composite Menu/tooltip with border + multi-depth + background ring
Complex 6-layer composite Elevated card with null resets + border + medium depth

Motion Tokens

Token Value Usage
--ds-motion-timing-swift cubic-bezier(.175, .885, .32, 1.1) Snappy overshoot easing
--ds-motion-overlay-scale .96 Overlay entrance scale
--ds-motion-overlay-duration .3s Overlay animation duration
--ds-motion-popover-duration .2s Popover animation (faster)

The "swift" timing function overshoots slightly (ending value 1.1), creating a subtle bounce that makes overlays feel alive without being playful.


7. Do's and Don'ts

Do's

  1. Do use shadow-as-border — Replace border: 1px solid with box-shadow: 0 0 0 1px for all container boundaries. This is Vercel's core visual technique.
  2. Do limit font weights to 400/500/600 — Never use 700 (bold). Emphasis comes from size and spacing, not weight. Semibold (600) is reserved for display headings only.
  3. Do apply aggressive negative letter-spacing on headlines — Use approximately -4% to -4.75% tracking at 32px+ sizes. Headlines should feel dense and engineered.
  4. Do use the double-ring focus pattern — Always implement 0 0 0 2px white, 0 0 0 4px blue for keyboard focus. The white inner ring ensures visibility on any background.
  5. Do keep color achromatic — The interface is black, white, and gray. Blue (#0072F5) is the only interactive color. Status colors appear only as small indicator dots.
  6. Do compose shadows in layers — Build elevation by stacking border-shadow + depth-shadow + background-border in a single box-shadow declaration.
  7. Do use the 4px spacing base — All spacing should be multiples of 4px, using the --geist-space-* token scale.

Don'ts

  1. Don't use CSS border for containers — Borders affect box-model layout. Use box-shadow: 0 0 0 1px instead for visual boundaries.
  2. Don't use font-weight 700 or higher — The Geist type system caps at 600 (semibold). Bold text violates the minimalist aesthetic and creates unnecessary visual weight.
  3. Don't introduce new accent colors — The interface is achromatic by design. If you need a new status color, use it only at indicator-dot scale (approximately 10px), never as backgrounds or large fills.
  4. Don't use decorative gradients or patterns — The only gradient in the system is --geist-text-gradient, a subtle black text effect. Background gradients, stripes, and patterns are absent.
  5. Don't animate with transform or opacity on interactive elements — Vercel buttons and links change only background-color and color on hover. No scale, translate, or fade effects.
  6. Don't use rounded corners larger than 12px on functional UIborder-radius: 6px is the standard. 12px is for cards. Pill shapes (9999px) are for badges and tags only.
  7. Don't add divider lines between sections — Vercel uses spacing (the --geist-space-gap system) and subtle surface color changes to separate content, not <hr> or border lines.

8. Responsive Behavior

45 Breakpoints: Component-Level Responsive Tuning

Vercel uses an unusually granular set of 45 breakpoints, far exceeding the typical 5-7 breakpoints of most design systems. This is not arbitrary — it reflects component-level responsive tuning where individual components define their own adaptation points.

Breakpoint Groups

Mobile (< 600px) — 13 breakpoints

px Likely Target
370, 374, 375 iPhone SE / iPhone 12 mini
383, 384 Pixel 5 / narrow Androids
400, 401 Wide phone threshold
427 iPhone 14 Pro Max
440, 450 Phablet territory
470, 480 Large phone / small tablet boundary
500 Max mobile width

Tablet (600-960px) — 10 breakpoints

px Likely Target
600, 601 Small tablet threshold
610, 640 Portrait tablet
650, 660, 670 Mid-tablet adjustments
750 Large portrait tablet
768, 769 iPad portrait (classic breakpoint)
800 Landscape phone / small landscape tablet

Desktop Small (960-1200px) — 12 breakpoints

px Likely Target
960, 961 Tablet landscape / small desktop
992 Bootstrap-legacy desktop
1000, 1020 Narrow desktop
1024 iPad landscape (classic)
1036, 1050 Sidebar-adjusted content
1080, 1100 Common laptop resolution
1108, 1120 Content width transitions
1150, 1151 Pre-max-width threshold

Desktop Large (1200px+) — 10 breakpoints

px Likely Target
1200 --geist-page-width — standard content max
1240, 1248, 1250 Content-with-margin region
1400 --ds-page-width — wide content max
1600 Large desktop / external monitor
2300 Ultrawide / 4K displays

Responsive Philosophy

The clustering of breakpoints around certain ranges reveals Vercel's approach:

  • 13 breakpoints below 600px — mobile is not one target, it is thirteen. Each component adapts independently.
  • Dense clustering at 1020-1150px — the critical laptop range gets per-component tuning where sidebar presence/absence creates many intermediate states.
  • Single jump from 1600 to 2300 — large screens get minimal special treatment; content is capped at --ds-page-width: 1400px.

9. Agent Prompt Guide

Quick Reference Tokens

Background:        #FAFAFA
Text primary:      #171717
Text secondary:    #4D4D4D
Interactive blue:  #0072F5
Focus blue:        #005FCC
Border shadow:     0 0 0 1px rgba(0,0,0,0.08)
Focus ring:        0 0 0 2px #FFF, 0 0 0 4px #0072F5
Font:              Geist Sans (400/500/600), Geist Mono (500)
Radius:            6px (default), 12px (cards), 9999px (pills)
Spacing base:      4px (use multiples: 8, 12, 16, 24, 32, 40, 48)
Page width:        1200px (standard), 1400px (wide)
Header height:     64px
Easing:            cubic-bezier(.175, .885, .32, 1.1)

Example Prompts

Prompt 1: Dashboard Card

"Create a dashboard metrics card. Background #FFFFFF, border using box-shadow: 0 0 0 1px rgba(0,0,0,0.08), no CSS border. Corner radius 6px. Title in Geist Sans 14px weight 500 color #171717. Value in 32px weight 600 with letter-spacing -1.28px. Subtitle in 12px weight 400 color #4D4D4D. Padding 24px. Status indicator as a 10px circle dot using the appropriate status color."

Prompt 2: Navigation Bar

"Build a fixed header, height 64px, background #FAFAFA, bottom border as box-shadow: 0 1px 0 0 rgba(0,0,0,0.1). Navigation items in Geist Sans 14px weight 400 color #4D4D4D. On hover: background #EBEBEB, text color #171717. On focus: double-ring shadow 0 0 0 2px #FFF, 0 0 0 4px #0072F5. Horizontal padding 24px, gap between items 32px. Logo area left-aligned."

Prompt 3: Dropdown Menu

"Design a dropdown menu using shadow elevation --ds-shadow-menu: box-shadow: 0 0 0 1px rgba(0,0,0,0.08), 0 1px 1px rgba(0,0,0,0.02), 0 4px 8px -4px rgba(0,0,0,0.04), 0 16px 24px -8px rgba(0,0,0,0.06). Background #FFFFFF, radius 12px. Menu items 14px weight 400, padding 8px 16px. Hover state: background #FAFAFA. Entrance animation: scale from 0.96 to 1.0 over 0.2s with cubic-bezier(.175, .885, .32, 1.1) easing."

Prompt 4: Form Input

"Create a text input, height 40px (--geist-form-height), font Geist Sans 14px weight 400. Border as box-shadow: 0 0 0 1px rgba(0,0,0,0.08). Radius 6px. Padding horizontal 12px. On focus: outline rgb(0, 95, 204) auto 1px, remove shadow border. Placeholder color #8F8F8F. Background transparent."

Prompt 5: Achromatic Page Layout

"Build a page layout: max-width 1200px, centered with 24px horizontal margin. Background #FAFAFA. Section spacing using 32px gaps. All text in Geist Sans. Hero heading: 48px weight 600, letter-spacing -2.28px, color #171717. Body text: 16px weight 400, line-height normal. Links in #0072F5, no underline by default. No decorative elements, no gradients, no colored backgrounds. Dividers as spacing only."


Generated by Sparkbites — extracted from live CSS analysis