UI design rules
Apply these seven rules whenever building or reviewing UI. Most bad UIs fail not on technical grounds, but on consistency, hierarchy, and missing systems.
1. No pure black / white
#000 on #fff is harsh and tiring.
- Soften to
#111 / #f5f5f5, or OKLCH equivalents such as oklch(18% 0 0) on oklch(98% 0 0).
- Use tokens —
var(--color-text) and var(--color-bg) — so both modes flip cleanly.
2. Consistent spacing — 8 px system
- Avoid arbitrary values (13 px, 22 px, 7 px).
- Stick to a scale: 8, 16, 24, 32, 48, 64 …
- Tailwind:
p-2 (8 px), p-4 (16 px), p-6 (24 px), p-8 (32 px).
- Use
--space-sm, --space-md, --space-lg tokens where defined.
3. Max 2 typefaces
- Many fonts = visual noise.
- 1–2 families plus varied weights.
- Typical split: UI sans (Inter), editorial serif (Lora) for long-form, monospace (Fira Code) for code.
- Vary weight and size before reaching for another family.
4. Color system — 60 / 30 / 10
| Share |
Role |
Examples |
| 60 % |
Background |
--color-bg, --color-bg-secondary |
| 30 % |
Surfaces |
--color-surface, cards, panels |
| 10 % |
Accent |
--color-accent, buttons, highlights |
Accent is reserved for actions and focal points — overusing it removes its meaning.
5. Clear type hierarchy
- Headings must step visually, not just in markup.
- Minimum 1.25×–1.5× step between levels.
h1 dominant, h2 clearly smaller, h3 body-adjacent.
- Use the defined text-scale tokens; don't freestyle sizes.
6. Readable line length
- Full-width running text fatigues the eye.
- Target 50–75 characters per line →
max-w-prose (65 ch) in Tailwind.
- Apply to article/blog body text. Navigation and UI elements are exempt.
7. Visual hierarchy — the most important rule
Every interactive element needs a tier:
| Tier |
Usage |
Style |
| Primary |
One dominant CTA per view |
Filled, accent color, high contrast |
| Secondary |
Supporting actions |
Outlined or muted |
| Ghost / tertiary |
Low-priority actions |
Text-only or subtle border |
Never have two primary buttons competing on the same screen. If everything shouts, nothing does.
8. Micro-detail rules (polish)
The details that separate "fine" from "feels crafted". Exact thresholds:
- Concentric border radius. Nested rounded elements:
outer = inner + padding. Same radius on parent and child is the most common thing that makes a UI feel off. Nested cards are always wrong anyway.
- Optical over geometric alignment. When geometric centering looks off (icons in buttons, play triangles, asymmetric glyphs), nudge it optically. Trust the eye, not the box model.
- Tabular numbers. Any number that updates in place (counters, timers, prices) gets
font-variant-numeric: tabular-nums — otherwise it reflows on every change.
- Text wrapping.
text-wrap: balance on headings (h1–h3), text-wrap: pretty on body prose to kill orphans.
- Minimum hit area 40×40px. Small controls (icon buttons, close X) extend their tap target with padding or a pseudo-element. Never let two hit areas overlap.
- Image outlines. A subtle
1px inset outline gives images consistent depth: rgba(0,0,0,0.1) in light mode, rgba(255,255,255,0.1) in dark — pure black/white, never a tinted near-black (it reads as dirt on the edge).
Quick checklist for new pages
1---2name: ui-design3description: Seven core UI rules for consistent, hierarchical, readable interfaces — colors, spacing, typography, and CTA tiers. Use when checking specific component consistency, reviewing layouts for visual hierarchy, or applying systematic spacing and color rules. For broader aesthetic direction and making design choices that don't look templated, use frontend-design instead.4---56# UI design rules78Apply these seven rules whenever building or reviewing UI. Most bad UIs fail not on technical grounds, but on consistency, hierarchy, and missing systems.910## 1. No pure black / white1112- `#000` on `#fff` is harsh and tiring.13- Soften to `#111` / `#f5f5f5`, or OKLCH equivalents such as `oklch(18% 0 0)` on `oklch(98% 0 0)`.14- Use tokens — `var(--color-text)` and `var(--color-bg)` — so both modes flip cleanly.1516## 2. Consistent spacing — 8 px system1718- Avoid arbitrary values (13 px, 22 px, 7 px).19- Stick to a scale: 8, 16, 24, 32, 48, 64 …20- Tailwind: `p-2` (8 px), `p-4` (16 px), `p-6` (24 px), `p-8` (32 px).21- Use `--space-sm`, `--space-md`, `--space-lg` tokens where defined.2223## 3. Max 2 typefaces2425- Many fonts = visual noise.26- 1–2 families plus varied weights.27- Typical split: UI sans (Inter), editorial serif (Lora) for long-form, monospace (Fira Code) for code.28- Vary weight and size before reaching for another family.2930## 4. Color system — 60 / 30 / 103132| Share | Role | Examples |33|---|---|---|34| 60 % | Background | `--color-bg`, `--color-bg-secondary` |35| 30 % | Surfaces | `--color-surface`, cards, panels |36| 10 % | Accent | `--color-accent`, buttons, highlights |3738Accent is reserved for actions and focal points — overusing it removes its meaning.3940## 5. Clear type hierarchy4142- Headings must step visually, not just in markup.43- Minimum 1.25×–1.5× step between levels.44- `h1` dominant, `h2` clearly smaller, `h3` body-adjacent.45- Use the defined text-scale tokens; don't freestyle sizes.4647## 6. Readable line length4849- Full-width running text fatigues the eye.50- Target 50–75 characters per line → `max-w-prose` (65 ch) in Tailwind.51- Apply to article/blog body text. Navigation and UI elements are exempt.5253## 7. Visual hierarchy — the most important rule5455Every interactive element needs a tier:5657| Tier | Usage | Style |58|---|---|---|59| Primary | One dominant CTA per view | Filled, accent color, high contrast |60| Secondary | Supporting actions | Outlined or muted |61| Ghost / tertiary | Low-priority actions | Text-only or subtle border |6263Never have two primary buttons competing on the same screen. If everything shouts, nothing does.6465## 8. Micro-detail rules (polish)6667The details that separate "fine" from "feels crafted". Exact thresholds:6869- **Concentric border radius.** Nested rounded elements: `outer = inner + padding`. Same radius on parent and child is the most common thing that makes a UI feel off. Nested cards are always wrong anyway.70- **Optical over geometric alignment.** When geometric centering looks off (icons in buttons, play triangles, asymmetric glyphs), nudge it optically. Trust the eye, not the box model.71- **Tabular numbers.** Any number that updates in place (counters, timers, prices) gets `font-variant-numeric: tabular-nums` — otherwise it reflows on every change.72- **Text wrapping.** `text-wrap: balance` on headings (h1–h3), `text-wrap: pretty` on body prose to kill orphans.73- **Minimum hit area 40×40px.** Small controls (icon buttons, close X) extend their tap target with padding or a pseudo-element. Never let two hit areas overlap.74- **Image outlines.** A subtle `1px` inset outline gives images consistent depth: `rgba(0,0,0,0.1)` in light mode, `rgba(255,255,255,0.1)` in dark — pure black/white, never a tinted near-black (it reads as dirt on the edge).7576## Quick checklist for new pages7778- [ ] No pure `#000` / `#fff` — design tokens in use?79- [ ] Spacing follows the 8 px grid?80- [ ] Max 2 font families?81- [ ] Accent color on ≤ 10 % of the surface?82- [ ] Heading sizes step clearly between levels?83- [ ] Body text constrained to ~65 ch?84- [ ] Only one primary CTA visible per section?