Back to Posthog

PostHog Design System

.interface-design/system.md

1.43.18.6 KB
Original Source

PostHog Design System

Extracted from codebase. Source of truth for UI consistency.

Spacing

  • Base unit: 4px (0.25rem)
  • Scale: 4, 8, 12, 16, 24, 32
  • Default gap: 8px (gap-2) — used in 55% of layouts
  • Default padding: 8px (p-2) or 16px (p-4)
  • Scene padding: var(--scene-padding)

Border Radius

TokenValueUsage
--radius-sm4px (0.25rem)Small elements, tags
--radius6px (0.375rem)Default — buttons, inputs, cards
--radius-lg10px (0.625rem)Popovers, menus, larger containers
full9999pxAvatars, pills, circular elements

Prefer rounded (default) for most elements. Use rounded-lg for popovers and elevated containers.

Depth Strategy

Borders-first. Shadows are rare and intentional.

  • Primary border: var(--color-border-primary) — posthog-3000 warm gray
  • Secondary border: var(--color-border-secondary) — darker variant
  • Semantic borders: --color-border-info, --color-border-warning, --color-border-error, --color-border-success
  • Default shadow: var(--shadow-elevation-3000) = 0 3px 0 <border-color> — only for elevated cards and toasts
  • Modal shadow: var(--modal-shadow-elevation) = 0px 16px 16px -16px rgb(0 0 0 / 35%)

Do not add shadows for general UI. Reserve for modals, dropdowns, and hover-elevated cards.

Colors

Accent

TokenLightDark
--color-accentHSL(19, 100%, 48%) orangeHSL(43, 94%, 57%) yellow
--color-accent-hover+10% lightness+10% lightness
--color-accent-active+15% lightness+15% lightness
--color-accent-invertedYellowOrange

Backgrounds

TokenLightDark
bg-primaryposthog-3000-50neutral-cool-950
bg-surface-primarywhiteneutral-cool-850
bg-surface-secondaryposthog-3000-100neutral-cool-900
bg-surface-tertiaryposthog-3000-150neutral-cool-950
bg-fill-primarywhiteneutral-cool-900
bg-fill-secondaryposthog-3000-25neutral-cool-850
bg-fill-tertiaryposthog-3000-50neutral-cool-800

Highlight fills (opacity-based)

Use bg-fill-highlight-{50,100,150,200} for subtle black overlays (light mode) or white overlays (dark mode). These use color-mix() for transparency.

Text

TokenLightDark
text-primaryneutral-950neutral-100
text-secondaryneutral-750neutral-350
text-tertiaryneutral-600neutral-400
text-successgreen-600green-400
text-warningyellow-700yellow-400
text-errorred-600red-400

Semantic

TokenValue
danger#db3707
warning#f7a501
success#388600

Data colors

15 series colors (--data-color-1 through --data-color-15) for charts. Some override in dark mode. Always use hex for Chart.js compatibility.

Brand

TokenValue
--brand-blue#1d4aff
--brand-red#f54e00
--brand-yellow#f9bd2b
--brand-key#000 (light) / #fff (dark)

Typography

PropertyValue
Base size14px
Line height1.5715
Font sans-apple-system, BlinkMacSystemFont, Inter, ...
Font titleMatterSQ, -apple-system, Inter, ...
Font monoui-monospace, SFMono-Regular, SF Mono, Menlo, ...
Font medium500
Font semibold600

Headings

LevelSizeWeightFont
h11.75rem500font-title
h21.3125rem500font-title
h31rem500font-title
h50.6875rem600font-title, uppercase, letter-spacing 0.075em

Component Patterns

Button (LemonButton)

SizeHeightH-PaddingV-PaddingFont Size
xxsmall20px4px2px0.6875rem
xsmall26px6px4px0.75rem
small33px8px8pxinherit
medium37px12px4px0.875rem
large49px12px12px1rem
  • Border radius: var(--radius) (6px)
  • Default size: medium

Input (LemonInput)

SizeHeightH-PaddingV-Padding
xsmall24px4px2px
small32px4px2px
medium37px8px4px
large48px
  • Border: 1px solid var(--color-border-primary)
  • Border radius: var(--radius) (6px)
  • Focus ring: box-shadow: 0 0 0 3px var(--color-bg-fill-highlight-75)

Card (LemonCard)

  • Border: 1px solid (default border color)
  • Padding: 24px (p-6)
  • Border radius: var(--radius) (6px)
  • Background: bg-surface-primary
  • Hover (when hoverEffect): box-shadow: var(--shadow-elevation-3000) + scale(1.01)
  • Border: 1px solid var(--border-bold)
  • Border radius: var(--radius) (6px)
  • Shadow: var(--modal-shadow-elevation)
  • Header/Content/Footer padding: 16px (1rem)
  • Backdrop: rgb(0 0 0 / 20%), blur 5px
  • Transition: 200ms

Popover / Menu

  • Background: bg-surface-primary
  • Border: 1px solid var(--color-border-primary)
  • Border radius: var(--radius-lg) (10px)
  • Shadow: var(--shadow-elevation-3000)
  • Min width: 8rem
  • Max width: 200px

Toast

  • Padding: 12px (0.75rem)
  • Border: 1px solid var(--secondary-3000-button-border)
  • Border radius: var(--radius) (6px)
  • Shadow: var(--shadow-elevation-3000)
  • Font: 0.875rem, weight 500

Layout

TokenValue
--project-navbar-width215px
--project-navbar-width-collapsed45px
--project-panel-width245px
--side-panel-bar-width40px

Breakpoints

TokenValue
sm576px
md768px
lg992px
xl1200px
2xl1600px

Dark Mode

  • Selector: [theme="dark"] on body
  • Tailwind: darkMode: ['selector', '[theme="dark"]']
  • Accent swaps: orange (light) / yellow (dark)
  • Surfaces swap to neutral-cool 800-950 range
  • Borders swap to neutral-cool 600-800

Z-Index Scale

TokenValue
--z-top9999
--z-bottom-notice1450
--z-tooltip1300
--z-popover1200
--z-modal1100
--z-hedgehog-buddy1050
--z-drawer900
--z-main-nav750
--z-lemon-sidebar700
--z-top-navigation550
--z-content-overlay500
--z-raised5

Animations

  • Focus ring transition: box-shadow 0.1s ease-in-out
  • Modal transition: 200ms
  • Fade in: 0.4s ease-out
  • Overlay fade: 0.2s ease-out
  • Disabled opacity: 0.65 (--opacity-disabled)

Component Library

Three-tier architecture:

  1. Primitives (frontend/src/lib/ui/) — Low-level React primitives (Button, Combobox, DropdownMenu, etc.)
  2. Lemon UI (frontend/src/lib/lemon-ui/) — 50+ published components (LemonButton, LemonInput, LemonModal, LemonTable, etc.)
  3. Composed components (frontend/src/lib/components/) — Feature-specific composed components built on Lemon UI

Always prefer Lemon UI components over custom implementations.