home / skills / dirnbauer / webconsulting-skills / ui-design-patterns

ui-design-patterns skill

/skills/ui-design-patterns

npx playbooks add skill dirnbauer/webconsulting-skills --skill ui-design-patterns

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
23.9 KB
---
name: ui-design-patterns
description: Practical UI design patterns and principles for creating polished, professional interfaces. Based on proven techniques from Refactoring UI and Practical UI.
version: 1.1.0
typo3_compatibility: "13.0 - 14.x"
triggers:
  - ui
  - design
  - layout
  - spacing
  - typography
  - color
  - hierarchy
  - styling
  - visual
  - accessibility
  - usability
  - contrast
---

# UI Design Patterns

Practical guidelines for creating polished, professional user interfaces without relying on graphic design talent. These patterns work for any web project, including TYPO3 frontend development.

## Acknowledgements

These patterns are adapted from two excellent resources:

- **Refactoring UI** by Adam Wathan & Steve Schoger — The definitive guide to practical UI design for developers
- **Practical UI** (2nd Edition) by Adham Dannaway — Quick and practical UI design guidelines for intuitive, accessible, and beautiful interfaces

We highly recommend both works for deepening your UI design knowledge.

---

## 0. Core Principles (from Practical UI)

Before diving into specific patterns, internalize these foundational principles:

### Minimize Usability Risks

Base design decisions on risk assessment—the risk that someone could have difficulty using an interface:

- Light grey text may look sleek but risks readability issues
- Icons without labels risk confusion about meaning
- Colored heading text risks being mistaken for links

**Always consider:** people with poor eyesight, low computer literacy, reduced dexterity, and cognitive differences.

### Have a Logical Reason for Every Design Detail

Every UI element should have a rationale. "That looks nice" is not constructive feedback. Be able to articulate *why* each design decision was made.

| Element | Logical Reason |
|---------|----------------|
| Left-aligned text | Creates neat edge, improves readability |
| Descriptive headings | Scannable, works with screen readers |
| Blue underlined links | Indicates interactivity, accessible for color blind |
| Grouped spacing | Related items closer together reduce cognitive load |

### Minimize Interaction Cost

Interaction cost = physical + mental effort to complete a task. Reduce it by:

1. **Keep related actions close** (Fitts's Law—closer/larger targets are faster to click)
2. **Reduce distractions** (avoid attention-grabbing elements that pull focus)
3. **Use progressive disclosure** (reveal complexity only when needed)

### Minimize Cognitive Load

Cognitive load is the mental effort required to use an interface. Reduce it by:

- Breaking information into smaller, digestible chunks
- Using familiar patterns people already understand
- Removing unnecessary elements and decisions
- Grouping related items visually

### Design System First

Create a system of reusable guidelines before designing:

- Color palette with usage rules
- Typography scale
- Spacing system
- Component patterns
- Interaction states

This ensures consistency and speeds up decision-making.

### Accessibility is Non-Negotiable

Meet **WCAG 2.1 Level AA** at minimum:

| Requirement | Minimum Ratio |
|-------------|---------------|
| Small text (≤18px) | 4.5:1 contrast |
| Large text (>18px bold or >24px) | 3:1 contrast |
| UI elements (borders, icons) | 3:1 contrast |

**Never rely on color alone**—always pair with icons, patterns, or text for color blind users.

### Use Common Design Patterns

Per Jakob's Law, stick with patterns people already know:

- Conventional form fields (not custom/unfamiliar styles)
- Standard navigation patterns
- Expected icon meanings
- Familiar button behaviors

Save creativity for your product's unique value proposition, not basic UI conventions.

### The 80/20 Rule

Roughly 80% of users use 20% of features. Prioritize the common paths:

- Optimize for frequent tasks, not edge cases
- Focus design effort where it has the largest impact
- Don't over-engineer rarely-used features

---

## 1. Starting from Scratch

### Start with a Feature, Not a Layout

Don't begin by designing the shell (navigation, sidebar, footer). Start with actual functionality.

**Wrong approach:**
- "Should it have a top nav or sidebar?"
- "Where should the logo go?"

**Right approach:**
- Design the core feature first (search form, product card, user profile)
- The navigation will reveal itself as you design features

### Detail Comes Later

In early stages, ignore typefaces, shadows, and icons. Use thick markers or low-fidelity wireframes to explore layouts quickly.

### Hold the Color

Design in grayscale first. This forces you to use spacing, contrast, and size to create hierarchy. Color comes later as enhancement.

### Work in Cycles

1. Design a simple version of the next feature
2. Build it
3. Iterate on the working design
4. Move to the next feature

### Be a Pessimist

Design the smallest useful version first. Don't design features you can't build yet—ship what works.

---

## 2. Hierarchy is Everything

### Not All Elements Are Equal

Visual hierarchy makes interfaces feel "designed". When everything competes for attention, nothing stands out.

**The key:** Deliberately de-emphasize secondary and tertiary information while highlighting what matters most.

### Size Isn't Everything

Don't rely solely on font size for hierarchy. Use:

| Technique | Effect |
|-----------|--------|
| **Font weight** | 600-700 for emphasis, 400-500 for normal |
| **Color contrast** | Dark for primary, grey for secondary, light grey for tertiary |
| **Spacing** | More space around important elements |

**Color guidelines for text:**
- Primary content: Dark color (e.g., `slate-900`)
- Secondary content: Medium grey (e.g., `slate-600`)
- Tertiary content: Light grey (e.g., `slate-400`)

### Don't Use Grey Text on Colored Backgrounds

Grey text on colored backgrounds looks washed out. Instead, pick a color with the same hue as the background, adjusting saturation and lightness.

```css
/* Bad: Grey on blue background */
background: hsl(220, 80%, 50%);
color: #888888; /* Looks dull */

/* Good: Tinted text matching background hue */
background: hsl(220, 80%, 50%);
color: hsl(220, 60%, 85%); /* Harmonious and readable */
```

### Emphasize by De-emphasizing

If a primary element doesn't stand out, don't make it louder—make competing elements quieter.

```css
/* Instead of making active nav item bolder... */
/* ...make inactive items softer */
.nav-item { color: var(--slate-400); }
.nav-item.active { color: var(--slate-900); }
```

### Labels Are a Last Resort

Context often eliminates the need for labels:

| Instead of | Use |
|------------|-----|
| "Email: [email protected]" | [email protected] (format is obvious) |
| "In stock: 12" | "12 left in stock" |
| "Bedrooms: 3" | "3 bedrooms" |

When labels are necessary, de-emphasize them—the data is what matters.

### Balance Weight and Contrast

Heavy elements (icons, bold text) can be de-emphasized with softer colors. Light elements (thin borders) can be emphasized with increased weight.

```css
/* Icon feels too heavy? Reduce contrast */
.icon { color: var(--slate-400); } /* Instead of slate-900 */

/* Border too subtle? Increase width */
border: 2px solid hsl(210, 23%, 95%); /* Instead of 1px darker */
```

### Button Hierarchy

Design buttons based on hierarchy, not just semantics:

| Type | Style | Use for |
|------|-------|---------|
| **Primary** | Solid, high contrast | Main action on page |
| **Secondary** | Outline or lower contrast | Less important actions |
| **Tertiary** | Link style | Seldom-used actions |

**Destructive actions** aren't automatically red and bold. If "Delete" isn't the primary action, style it as secondary or tertiary, then use bold red styling in the confirmation modal.

---

## 3. Layout and Spacing

### Start with Too Much White Space

Begin with excessive space, then remove until satisfied. This ensures elements breathe properly.

### Establish a Spacing System

Use a constrained scale with meaningful jumps (~25% between values):

```
4px, 8px, 12px, 16px, 24px, 32px, 48px, 64px, 96px, 128px
```

**Base on 16px** (default browser font size, divides nicely).

### You Don't Have to Fill the Screen

If content only needs 600px, don't stretch it to 1200px. Extra space around edges never hurts.

### Shrink the Canvas

Designing for mobile first often reveals better solutions. Start with ~400px width, then expand.

### Grids Are Overrated

Not all elements should be fluid. Sidebars, icons, and avatars often work better with fixed sizes while main content flexes.

```css
/* Better than percentage-based sidebar */
.sidebar { width: 280px; flex-shrink: 0; }
.main { flex: 1; min-width: 0; }
```

### Relative Sizing Doesn't Scale

Headlines shouldn't stay proportional to body text across screen sizes. Large elements should shrink faster than small ones on mobile.

```css
/* Desktop: 45px headline, 18px body (2.5x ratio) */
/* Mobile: 24px headline, 14px body (1.7x ratio) */
```

### Avoid Ambiguous Spacing

When elements are grouped without visible separators, the spacing between groups must be greater than spacing within groups.

```css
/* Form labels should be closer to their inputs than to previous inputs */
.form-group { margin-bottom: 24px; }
.form-label { margin-bottom: 8px; }
```

---

## 4. Designing Text

### Establish a Type Scale

Hand-pick sizes rather than using mathematical ratios:

```
12px, 14px, 16px, 18px, 20px, 24px, 30px, 36px, 48px, 60px, 72px
```

Use `px` or `rem`, not `em` (to avoid compounding issues with nesting).

### Use Good Fonts

**Safe choices:**
- System font stack for familiarity
- Fonts with 5+ weights indicate quality craftsmanship
- High x-height fonts for UI text (better legibility at small sizes)

**Filter by weight count** on Google Fonts to find quality options.

### Keep Line Length in Check

Optimal: **45-75 characters per line** (20-35em width).

```css
.prose { max-width: 65ch; } /* Character-based width */
```

### Baseline, Not Center

When mixing font sizes on one line, align by baseline, not vertical center.

```css
.header-row { align-items: baseline; } /* Not center */
```

### Line Height Is Proportional

| Font Size | Line Height |
|-----------|-------------|
| Small text (14px) | 1.5-1.75 |
| Body (16-18px) | 1.5-1.65 |
| Headlines (24px+) | 1.1-1.25 |
| Large headlines (36px+) | 1.0-1.1 |

Wider paragraphs need taller line heights.

### Not Every Link Needs a Color

In link-heavy interfaces, use subtle differentiation (font weight, darker color) instead of blue underlines everywhere. Reserve bold link styling for important navigation.

### Align with Readability in Mind

- **Left-align** most text
- **Center** only short, independent blocks (headings, CTAs)
- **Right-align** numbers in tables for easy comparison
- **Hyphenate** justified text

### Use Letter-Spacing Effectively

- **Tighten** headlines slightly: `letter-spacing: -0.02em;`
- **Widen** all-caps text: `letter-spacing: 0.05em;`
- Leave body text alone

---

## 5. Working with Color

### Ditch Hex for HSL

HSL (Hue, Saturation, Lightness) makes color relationships intuitive:

```css
/* HSL is easier to reason about */
--primary-500: hsl(220, 80%, 50%);
--primary-600: hsl(220, 80%, 40%); /* Just darken lightness */
--primary-400: hsl(220, 80%, 60%); /* Just lighten */
```

### You Need More Colors Than You Think

A complete palette includes:

| Category | Shades Needed |
|----------|---------------|
| **Greys** | 8-10 shades (true black looks unnatural) |
| **Primary** | 5-10 shades |
| **Accent colors** | 5-10 shades each (red, yellow, green, etc.) |

### Define Shades Up Front

Don't use `lighten()` or `darken()` functions. Pre-define all shades:

1. Pick your **base** color (good for button backgrounds)
2. Pick your **darkest** shade (for text on light backgrounds)
3. Pick your **lightest** shade (for tinted backgrounds)
4. Fill in 6-7 shades between them

### Don't Let Lightness Kill Saturation

As lightness approaches 0% or 100%, increase saturation to maintain vibrancy.

### Perceived Brightness Varies by Hue

Yellow appears brighter than blue at the same lightness. To make a color lighter without washing it out, rotate hue toward yellow, cyan, or magenta. To darken, rotate toward red, green, or blue.

### Greys Don't Have to Be Grey

Saturate greys slightly for personality:
- **Cool greys**: Add blue (hue ~210)
- **Warm greys**: Add yellow/orange (hue ~40)

```css
--grey-500: hsl(210, 10%, 50%); /* Cool grey */
--grey-500-warm: hsl(40, 10%, 50%); /* Warm grey */
```

### Accessible Contrast

| Text Type | Minimum Ratio |
|-----------|---------------|
| Body text (<18px) | 4.5:1 |
| Large text (18px+ bold or 24px+) | 3:1 |

**Flip the contrast** when colored backgrounds make white text too dark—use dark colored text on light colored backgrounds instead.

### Don't Rely on Color Alone

Always pair color with another indicator (icons, patterns, text) for colorblind users.

### System Colors for Status

Use traffic light colors with familiar meanings:

| Color | Usage | When to Use |
|-------|-------|-------------|
| **Red** | Error | Negative messages, failures requiring attention |
| **Amber** | Warning | Caution, potentially risky actions |
| **Green** | Success | Positive messages, completed actions |

Always pair with icons for color blind accessibility.

### APCA: The Future of Contrast Measurement

WCAG 3 introduces the **Accessible Perceptual Contrast Algorithm (APCA)**—a more accurate contrast measurement:

| APCA Value | Use For |
|------------|---------|
| ≥90 | Preferred for body text (14px+) |
| ≥75 | Minimum for body text (18px+) |
| ≥60 | Other text (24px or 16px bold+) |
| ≥45 | Large text (36px or 24px bold+), UI elements |
| ≥30 | Placeholder text, disabled buttons |
| ≥15 | Non-text decorative elements |

**Key difference:** APCA handles dark backgrounds better than WCAG 2, and swapping text/background colors affects the score.

### Transparent Colors for Flexibility

Use transparent colors (with alpha values) for:

- Hover states that work on any background
- Overlays that adapt to underlying content
- Subtle backgrounds that maintain harmony

```css
/* Transparent overlays that work on any background */
--hover-overlay: hsla(0, 0%, 0%, 0.05);
--active-overlay: hsla(0, 0%, 0%, 0.1);
--disabled-overlay: hsla(0, 0%, 100%, 0.5);
```

---

## 6. Creating Depth

### Emulate a Light Source

Light comes from above. Apply this consistently:

- **Raised elements**: Lighter top edge, shadow below
- **Inset elements**: Shadow at top, lighter bottom edge

```css
/* Raised button */
.button {
  box-shadow: 
    inset 0 1px 0 hsl(220, 80%, 70%), /* Light top edge */
    0 1px 3px hsla(0, 0%, 0%, 0.2);    /* Shadow below */
}

/* Inset input */
.input {
  box-shadow: inset 0 2px 4px hsla(0, 0%, 0%, 0.1);
}
```

### Use Shadows to Convey Elevation

| Elevation | Shadow | Use for |
|-----------|--------|---------|
| Low | `0 1px 3px rgba(0,0,0,0.12)` | Buttons, cards |
| Medium | `0 4px 6px rgba(0,0,0,0.1)` | Dropdowns, popovers |
| High | `0 15px 35px rgba(0,0,0,0.15)` | Modals, dialogs |

Define 5 shadow levels and stick to them.

### Shadows Can Have Two Parts

Combine a large soft shadow (direct light) with a small tight shadow (ambient occlusion):

```css
box-shadow: 
  0 4px 6px rgba(0, 0, 0, 0.07),   /* Large, soft */
  0 1px 3px rgba(0, 0, 0, 0.1);    /* Small, tight */
```

The tight shadow fades at higher elevations.

### Flat Designs Can Have Depth

Without shadows:
- Use **lighter colors** for raised elements
- Use **darker colors** for inset elements
- Use **solid offset shadows** (no blur) for flat aesthetic with depth

### Overlap Elements to Create Layers

Let cards cross background boundaries. Overlap images with invisible borders to prevent clashing.

---

## 7. Working with Images

### Use Good Photos

Bad photos ruin designs. Hire professionals or use quality stock (Unsplash, etc.). Don't use smartphone placeholders.

### Text on Images Needs Consistent Contrast

When placing text over images:

1. **Add overlay**: Semi-transparent black (for light text) or white (for dark text)
2. **Lower contrast**: Reduce image contrast, adjust brightness
3. **Colorize**: Desaturate + multiply blend with brand color
4. **Text shadow**: Large blur radius, no offset (glow effect)

### Everything Has an Intended Size

- **Don't scale up icons** designed for 16-24px—they look chunky
- **Don't scale down screenshots**—details become illegible
- **Redraw logos** for small sizes (favicons)

Wrap small icons in colored shapes to fill larger spaces:

```html
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
  <svg class="w-6 h-6 text-blue-600"><!-- Icon --></svg>
</div>
```

### User-Uploaded Content

- Force consistent aspect ratios with `object-fit: cover`
- Prevent background bleed with subtle inner shadows
- Control dimensions with fixed containers

```css
.user-image {
  object-fit: cover;
  aspect-ratio: 16/9;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
}
```

---

## 8. Copywriting for UI

Clear interface text is as important as visual design. Poor copy creates confusion and increases cognitive load.

### Be Concise

Remove unnecessary words. Every word should earn its place.

| Verbose | Concise |
|---------|---------|
| "Click here to submit your form" | "Submit" |
| "In order to continue, please..." | "To continue..." |
| "Are you sure you want to delete?" | "Delete this item?" |

### Use Sentence Case

Sentence case is easier to read than Title Case or ALL CAPS:

- **Good:** "Create new account"
- **Avoid:** "Create New Account"
- **Never:** "CREATE NEW ACCOUNT"

### Front-Load Text

Put the most important information first. Users scan—don't bury key info.

| Back-loaded | Front-loaded |
|-------------|--------------|
| "To reset your password, click here" | "Reset password" |
| "If you need help, contact support" | "Contact support for help" |

### Use Plain Language

Write at an 8th-grade reading level. Avoid jargon and technical terms.

| Complex | Simple |
|---------|--------|
| "Authenticate your credentials" | "Sign in" |
| "Terminate session" | "Log out" |
| "Insufficient permissions" | "You don't have access" |

### Write Clear Error Messages

Good error messages:

1. **Explain what happened** (not just "Error")
2. **Suggest how to fix it** (actionable guidance)
3. **Use human language** (not error codes)

| Bad | Good |
|-----|------|
| "Error 403" | "You don't have permission to view this page" |
| "Invalid input" | "Please enter a valid email address" |
| "Request failed" | "Couldn't save changes. Check your connection and try again" |

### Consistent Vocabulary

Use the same words for the same concepts throughout:

- Pick "Sign in" or "Log in"—not both
- Pick "Settings" or "Preferences"—not both
- Pick "Delete" or "Remove"—not both

### Button Labels

Use action verbs that describe what happens:

| Vague | Specific |
|-------|----------|
| "OK" | "Save changes" |
| "Submit" | "Create account" |
| "Yes" | "Delete message" |

---

## 9. Forms and Buttons

### Button Weights

Define three distinct button styles based on importance:

| Weight | Style | Use For |
|--------|-------|---------|
| **Primary** | Solid, high contrast, brand color | Main action (one per screen) |
| **Secondary** | Outline or muted fill | Alternative actions |
| **Tertiary** | Text-only, link style | Least important actions |

### Form Field Best Practices

1. **Use conventional styles**—don't reinvent form fields
2. **Visible borders**—minimum 3:1 contrast ratio
3. **Clear focus states**—visible keyboard focus indicators
4. **Inline validation**—show errors as users type, not only on submit
5. **Helpful placeholders**—example input, not labels

### Form Layout

- **One column** for most forms (faster to complete)
- **Group related fields** with clear visual separation
- **Labels above inputs** (faster scanning than left-aligned labels)
- **Required field indicators**—mark optional fields, not required ones

### Avoid Disabled Buttons

Disabled buttons create confusion. Instead:

- Hide buttons until they're usable
- Show buttons but explain why action isn't available
- Use inline validation to guide users

```css
/* If you must use disabled buttons */
.button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
```

---

## 10. Finishing Touches

### Supercharge the Defaults

| Default | Upgrade |
|---------|---------|
| Bullet points | Custom icons (checkmarks, locks, stars) |
| Quote marks | Large, colored quote symbols |
| Links | Bold, custom underline overlapping text |
| Checkboxes | Brand-colored custom controls |

### Add Color with Accent Borders

A 4px colored border adds polish without design skills:

```css
/* Top of cards */
.card { border-top: 4px solid var(--primary-500); }

/* Side of alerts */
.alert { border-left: 4px solid var(--warning-500); }

/* Under headlines */
.headline::after { 
  content: '';
  display: block;
  width: 60px;
  height: 4px;
  background: var(--primary-500);
  margin-top: 12px;
}
```

### Decorate Backgrounds

Break monotony with:
- Subtle background color changes between sections
- Gradients (keep hues within 30° of each other)
- Low-contrast repeating patterns
- Simple geometric shapes or illustrations

### Don't Overlook Empty States

Empty states are first impressions. Include:
- Illustrations or icons
- Clear call-to-action
- Hide filters/tabs until content exists

### Use Fewer Borders

Instead of borders for separation:

| Alternative | When to Use |
|-------------|-------------|
| Box shadows | Outline elements on same-color backgrounds |
| Different background colors | Adjacent sections |
| Extra spacing | Group separation |

### Think Outside the Box

Challenge assumptions about component design:
- Dropdowns can have multiple columns, icons, and descriptions
- Tables can combine columns and add hierarchy
- Radio buttons can be selectable cards
- Forms can use creative layouts

---

## 11. Leveling Up

### Look for Decisions You Wouldn't Have Made

Study designs you admire. Notice unconventional choices:
- Inverted datepicker colors
- Buttons inside inputs
- Two-color headlines

### Rebuild Favorite Interfaces

Recreate designs from scratch without inspecting code. Discovering why your version differs teaches lasting lessons.

---

## Quick Reference: System Recommendations

### Spacing Scale

```css
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--space-8: 32px;
--space-12: 48px;
--space-16: 64px;
--space-24: 96px;
--space-32: 128px;
```

### Type Scale

```css
--text-xs: 12px;
--text-sm: 14px;
--text-base: 16px;
--text-lg: 18px;
--text-xl: 20px;
--text-2xl: 24px;
--text-3xl: 30px;
--text-4xl: 36px;
--text-5xl: 48px;
--text-6xl: 60px;
```

### Shadow Scale

```css
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
--shadow-xl: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
--shadow-2xl: 0 20px 25px rgba(0, 0, 0, 0.15), 0 10px 10px rgba(0, 0, 0, 0.04);
```

### Border Radius Scale

```css
--radius-sm: 2px;
--radius-md: 4px;
--radius-lg: 8px;
--radius-xl: 12px;
--radius-2xl: 16px;
--radius-full: 9999px;
```

### Interaction States

Every interactive element needs clear state feedback:

```css
/* Button states example */
.button {
  background: var(--primary-500);
  transition: all 0.15s ease;
}
.button:hover {
  background: var(--primary-600);
}
.button:active {
  background: var(--primary-700);
  transform: translateY(1px);
}
.button:focus-visible {
  outline: 2px solid var(--primary-500);
  outline-offset: 2px;
}
.button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
```

### WCAG 2.1 AA Checklist

| Requirement | Target |
|-------------|--------|
| Text contrast (small) | 4.5:1 minimum |
| Text contrast (large) | 3:1 minimum |
| UI component contrast | 3:1 minimum |
| Focus indicators | Visible, 3:1 contrast |
| Touch targets | 44×44px minimum |
| Color independence | Never color alone |
| Text resize | Works at 200% zoom |

---

*For deeper learning, study the source materials: [Refactoring UI](https://www.refactoringui.com/) and [Practical UI](https://www.practical-ui.com/)*