Home
cd ../playbooks
Developer ToolsIntermediate

Frontend UX Pattern Library

Concrete, research-backed patterns for SaaS dashboards, landing pages, and forms — plus accessibility requirements, Tailwind implementation gotchas, and a pre-delivery checklist that treats accessibility as a launch blocker, not a nice-to-have.

5 minutes
By majidmanzarpourSource
#frontend#ux-patterns#accessibility#tailwind#react#saas-dashboard#landing-page#conversion-optimization#wcag

Your form has 11 fields, asks for a phone number nobody needs, and validates on every keystroke — three separate, measured ways to tank conversion, and none of them show up as a bug because the page still technically works.

Who it's for: frontend developers who want concrete UX patterns instead of vague design advice, indie hackers building a SaaS dashboard or landing page without a designer, teams wanting an accessibility checklist that's actually specific enough to act on, React/Tailwind developers who keep hitting the same dynamic-class-name bug, anyone shipping a form who wants the conversion research instead of guessing

Example

"Build a settings page and a signup form for our dashboard" → Settings laid out as bucket + side panel with destructive actions grouped in a Danger Zone, signup form built as a single-column 4-field layout instead of 11 (a measured 120% conversion difference), every input properly labeled and validated on blur, and a pre-delivery checklist confirming touch targets, contrast, and focus states before calling it done

CLAUDE.md Template

New here? 3-minute setup guide → | Already set up? Copy the template below.

# Frontend UX Pattern Library

## Your Role

You build production-grade frontend interfaces using concrete, research-backed patterns for SaaS dashboards, landing pages, forms, and components — not vague "make it look good" guidance. Every recommendation here has a specific reason: a conversion study, an accessibility requirement, or a documented technical failure mode.

This is a pattern library and a pre-delivery checklist, not an aesthetic-direction exercise — pair it with your own design-token/palette decisions for the visual layer.

---

## SaaS Dashboard Patterns

### Layout architecture

```
┌─────────────────────────────────────────────────┐
│ Top Bar (56-64px): Logo, Search, User Menu      │
├──────────┬──────────────────────────────────────┤
│ Sidebar  │  Main Content Area                   │
│ 240-280px│  (with breadcrumbs if deep nav)      │
│ collapsed│                                       │
│ 64-80px  │  Cards / Data / Forms                │
└──────────┴──────────────────────────────────────┘
```

### Navigation pattern by scope

| Scenario | Pattern |
|----------|---------|
| 10+ sections | Collapsible sidebar |
| 3–6 sections | Top navigation |
| Secondary nav | Tabs, max 6 |
| Deep hierarchy | Breadcrumbs |

### Content hierarchy

1. **Value-first metrics**: "You saved 4 hours" communicates more than a raw number
2. **Actionable insights**: what should the user actually do next, not just what happened
3. **Progressive disclosure**: summary first, detail on demand — don't front-load every field
4. **Role-based views**: different personas need different default data, not one dashboard for everyone

### Data visualization
- Semantic color (red = negative, green = positive) always backed by a pattern or icon too — color alone excludes colorblind users
- Legends always included, axis labels mandatory
- Truncate long labels with a tooltip rather than letting them collide or wrap unpredictably

### Empty states

```jsx
// Good — helpful, action-oriented
<EmptyState
  icon={<InboxIcon />}
  title="No messages yet"
  description="When you receive messages, they'll appear here."
  action={<Button>Compose message</Button>}
/>

// Bad — a dead end
<p>No data</p>
```

### Settings pages
- Bucket + side panel layout for anything with more than a handful of settings
- Group destructive actions in a "Danger Zone" at the bottom, visually separated
- Destructive confirmations require typing the resource name or a specific label ("Delete account," never a generic "Yes")

### Toast/notification timing
- Default: 4–5 seconds
- Accessibility minimum: 6 seconds — shorter and screen reader users can't finish reading before it disappears
- Formula: 500ms per word + 3 seconds base
- Always include a manual dismiss button — auto-dismiss alone isn't sufficient for users who read slower than average

---

## Landing Page Patterns

### Above-the-fold, no exceptions
1. Clear headline, 5–10 words
2. Supporting subheadline stating the value proposition
3. Single primary CTA
4. A visual element — hero image, illustration, or product shot

### Section flow
```
1. Hero (headline + CTA + visual)
2. Social proof (logos, testimonial snippet)
3. Problem/Solution
4. Features/Benefits (3-4 max — more dilutes the pitch)
5. Detailed testimonials
6. Pricing (if applicable)
7. FAQ
8. Final CTA
9. Footer
```

### CTA button design
- Minimum 44px height, padding roughly 2× the font size
- High contrast; warm colors read as more urgent
- Action verbs, first-person: "Get my free trial" outperforms "Sign up"
- 2–5 words maximum

### Social proof placement
- Logo bar: immediately after the hero
- Testimonials: near points of likely objection
- Stats: near pricing
- Trust badges: near forms or checkout

### Pricing tables
- 3–4 tiers maximum — more causes decision paralysis
- Highlight the recommended tier explicitly ("Most Popular")
- Annual/monthly toggle with the savings shown, not just implied
- Checkmarks for fast feature scanning
- A CTA button on every tier, not just the highlighted one

### Form optimization — these are measured effects, not opinions
- Single-column layout: **120% fewer errors** than multi-column
- Minimizing fields: 4 fields vs. 11 fields → **120% more conversions**
- Never ask for a phone number unless essential — **58% abandonment** when required unnecessarily
- Labels above inputs, not placeholder-as-label
- Validate on blur, not while typing — validating mid-keystroke reads as impatient and produces false-negative errors on incomplete input

---

## Accessibility — Concrete Requirements, Not Suggestions

### Contrast and targets

| Element | Minimum |
|---------|---------|
| Body text contrast | 4.5:1 |
| UI element contrast | 3:1 |
| Focus indicator contrast | 3:1 against adjacent color |
| Touch target size | 44×44px (Apple/WCAG) or 48×48dp (Material) |
| Touch target spacing | 8px minimum between adjacent targets |

A touch target can extend past its visual boundary via padding — the visible element doesn't need to be the full 44px if the tappable area is.

### Interactive elements
- Every interactive element has a visible focus state — **never `outline: none` without a replacement**
- Focus indicators need 3:1 contrast against whatever's next to them
- Tab order must be logical — avoid `tabindex` values above 0, which silently breaks natural reading order

### Forms
- Every input has an associated `<label>` — not just a placeholder, which disappears the moment typing starts
- Error messages are programmatically associated via `aria-describedby`, not just visually adjacent
- Never disable a submit button before the user has attempted submission — it hides validation state instead of surfacing it
- Use `autocomplete` attributes where they apply

### Images and icons
- Meaningful images get descriptive `alt` text
- Decorative images get `alt=""` or `aria-hidden="true"` — an empty but present alt, not a missing attribute
- Icon-only buttons require `aria-label`
- SVG icons: `role="img"` + `aria-label`, or `aria-hidden="true"` if purely decorative

### Semantic HTML — the first rule of ARIA is not needing it

```html
<!-- Correct -->
<button type="button">Click me</button>
<a href="/page">Navigate</a>

<!-- Wrong -->
<div onclick="...">Click me</div>
<span class="link">Navigate</span>
```

Don't reach for ARIA attributes when a native HTML element already carries the correct semantics and keyboard behavior for free.

---

## Tailwind CSS Implementation

### The `cn()` helper — use it for every conditional class

```typescript
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}
```

### Never construct dynamic class names — Tailwind's build purges them

```typescript
// Broken — this class string doesn't exist anywhere in source at build time,
// so Tailwind's purge step removes it and nothing renders
const color = "blue";
<div className={`bg-${color}-500`} />

// Correct — every literal class string is present in source for purge to find
const colorMap = { blue: "bg-blue-500", red: "bg-red-500", green: "bg-green-500" };
<div className={colorMap[color]} />
```

This is one of the most common silent frontend bugs — the code looks correct, compiles, and just renders unstyled in production.

### Component variants with CVA

```typescript
import { cva, type VariantProps } from "class-variance-authority";

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent",
        ghost: "hover:bg-accent hover:text-accent-foreground",
      },
      size: {
        sm: "h-9 px-3 text-sm",
        default: "h-10 px-4 py-2",
        lg: "h-11 px-8 text-base",
      },
    },
    defaultVariants: { variant: "default", size: "default" },
  }
);
```

### Mobile-first, always

```html
<div class="
  flex flex-col          /* Mobile: stack */
  md:flex-row            /* Tablet+: row */
  gap-4 md:gap-8
  p-4 md:p-6 lg:p-8
">
```

Breakpoints: `sm` 640px · `md` 768px · `lg` 1024px · `xl` 1280px · `2xl` 1536px.

### Dark mode — class-based, not media-query-only

```html
<div class="bg-white dark:bg-slate-900 text-slate-900 dark:text-white">
```

---

## React Component Patterns

### Compound components over prop soup

```tsx
// Prop soup:
<Tabs defaultValue="tab1" items={[...]} onChange={...} />

// Composition:
<Tabs defaultValue="tab1">
  <TabsList>
    <TabsTrigger value="tab1">Tab 1</TabsTrigger>
    <TabsTrigger value="tab2">Tab 2</TabsTrigger>
  </TabsList>
  <TabsContent value="tab1">Content 1</TabsContent>
  <TabsContent value="tab2">Content 2</TabsContent>
</Tabs>
```

### Respect reduced motion

```tsx
const shouldReduceMotion = useReducedMotion();

<motion.div
  initial={{ opacity: 0, y: shouldReduceMotion ? 0 : 20 }}
  animate={{ opacity: 1, y: 0 }}
  transition={{ duration: shouldReduceMotion ? 0 : 0.3 }}
/>
```

### Skeleton screens over spinners

```tsx
<div className="animate-pulse">
  <div className="h-4 bg-muted rounded w-3/4 mb-2" />
  <div className="h-4 bg-muted rounded w-1/2" />
</div>
```

Skeletons preview the actual layout that's loading; a spinner communicates nothing about what's coming.

---

## Anti-Patterns

**Visual**: purple/blue gradients on white (the single most recognizable AI-generated look) · inconsistent border-radius — pick one value and hold it · more than 3 font weights in one interface · shadows that don't match a consistent light source

**UX/dark patterns**: confirmshaming ("No thanks, I hate saving money") · pre-selected options that benefit the company over the user · cancellation made harder than signup · fake urgency or scarcity indicators · infinite scroll with no pagination fallback — breaks the back button and keyboard navigation

**Technical**: `outline: none` with no focus replacement · `<div onclick>` instead of `<button>` · dynamic Tailwind class construction · animating layout properties (width, height, margin — animate `transform`/`opacity` instead) · reading layout properties inside a loop, which causes layout thrashing

**Mobile**: touch targets under 44×44px · body text under 16px · horizontal scroll on content · no tap feedback within 100ms · fixed elements sitting in the thumb zone

---

## Pre-Delivery Checklist

Run this before calling any frontend work done — not as a courtesy pass, as a gate.

**Accessibility**
- [ ] Color contrast ≥ 4.5:1 text / 3:1 UI
- [ ] Touch targets ≥ 44×44px
- [ ] Every image has `alt` text
- [ ] Every form field has a `<label>`
- [ ] Visible focus states on every interactive element
- [ ] No color-only information

**Visual design**
- [ ] Clear typographic hierarchy, 3–5 levels
- [ ] Consistent spacing from one token scale
- [ ] 2–3 typefaces maximum
- [ ] One memorable design element, not zero and not five competing ones

**Technical**
- [ ] Mobile-first responsive approach
- [ ] Animations use only `transform`/`opacity`
- [ ] No dynamic Tailwind class names
- [ ] `cn()` helper used for class merging
- [ ] Dark mode via CSS variables
- [ ] `prefers-reduced-motion` respected

**UX integrity**
- [ ] Single primary goal per page
- [ ] No dark patterns or confirmshaming
- [ ] Footer always accessible
- [ ] Error states are actually helpful, not just present
- [ ] Loading states exist for every async operation

---

## Rules

- Every accessibility item above is a requirement, not a nice-to-have — treat contrast, labels, and focus states as launch blockers
- Never construct a Tailwind class dynamically from a variable — use an explicit lookup map every time
- Validate forms on blur, never on every keystroke
- Animate only `transform` and `opacity` — anything else risks layout thrashing
- Run the full pre-delivery checklist before considering any frontend work complete
README.md

What This Does

A pattern library for the parts of frontend UX that have a right answer, not just a style preference: SaaS dashboard layout architecture, landing page section flow, form field counts backed by actual conversion research, toast timing formulas, and a WCAG accessibility checklist specific enough to act on directly rather than "make it accessible."

Pairs well with a separate aesthetic-direction playbook for the visual/brand layer — this one covers structure, conversion, accessibility, and the specific Tailwind/React implementation traps that produce silent bugs.


Quick Start

Step 1: Create a Project Folder

mkdir frontend-patterns && cd frontend-patterns

Step 2: Download the Template

Click Download above, then:

mv ~/Downloads/CLAUDE.md ./

Step 3: Build a Component or Page

claude

Then ask: "Build a settings page for our dashboard" or "Review this landing page against the pre-delivery checklist"


What's Covered

Area Includes
SaaS dashboards Layout architecture, navigation-by-scope rules, empty states, settings page conventions, toast timing formula
Landing pages Above-the-fold requirements, section flow, CTA design, pricing table rules, social proof placement
Forms Research-backed field-count and layout guidance
Accessibility Contrast ratios, touch target sizing, focus states, form labeling, semantic HTML
Tailwind/React The dynamic-class-name purge bug, cn() helper pattern, CVA variants, reduced-motion handling

Research-Backed Form Numbers

  • Single-column forms: 120% fewer errors than multi-column
  • 4 fields vs. 11 fields: 120% more conversions
  • Requiring a phone number unnecessarily: 58% abandonment

Tips & Best Practices

  • Never construct a Tailwind class name dynamically. `bg-${color}-500` gets purged at build time because Tailwind scans for literal class strings — the code compiles fine and renders unstyled in production. Use an explicit lookup object instead; this is one of the most common silent frontend bugs.
  • Validate forms on blur, not on every keystroke. Mid-keystroke validation flags incomplete input as an error before the user has finished typing, which reads as impatient and produces false negatives.
  • Toast duration has an accessibility floor, not just a default. 4-5 seconds is the norm, but 6 seconds is the accessibility minimum — shorter and screen reader users can't finish reading before it auto-dismisses.
  • Destructive confirmations require typing the resource name or a specific label, never a generic "Yes" — this is a deliberate friction point, not an oversight to streamline away.
  • The pre-delivery checklist is a gate, not a courtesy pass. Treat every accessibility item — contrast, touch targets, labels, focus states — as a launch blocker rather than a follow-up ticket.

Limitations

  • This is a structural and technical pattern library, not an aesthetic-direction guide — for palette, typography personality, and avoiding the "generic AI look," pair it with a design-direction playbook
  • The Tailwind/React implementation section assumes that specific stack — the dashboard, landing page, and accessibility guidance is stack-agnostic, but the code patterns are Tailwind/React-specific
  • Conversion statistics (form field counts, phone number abandonment) are general findings, not guarantees for every product — validate with your own funnel data where it matters

$Related Playbooks

Developer Tools

Git Commit & PR Automation

Three streamlined git workflows: commit with an auto-drafted message matching your repo's style, ship a full commit-push-PR in one step, and clean up branches deleted on the remote.

5 minutes
Beginner
Developer Tools

AI Crawler Access Audit: Who Can Actually Read Your Site

Maps 14 AI crawlers against your robots.txt, meta tags, and HTTP headers, then returns an access score and the exact rules to change

10 minutes
Intermediate
Developer Tools

llms.txt Generator & Auditor

Generate and validate llms.txt, the root-level Markdown file that tells AI systems what your site is and which pages to cite

10 minutes
Intermediate
Developer Tools

GEO Schema: Structured Data for AI Citation

Audit and generate schema.org JSON-LD built for AI comprehension, with a sameAs entity graph, knowsAbout topics, and a 0-100 scoring rubric

10 minutes
Intermediate
Developer Tools

GEO Technical SEO Audit: 8 Categories, 100 Points

A scored technical audit covering crawlability, indexability, security, Core Web Vitals, and the server-side rendering check that decides whether AI crawlers see your content at all

15 minutes
Advanced
Developer Tools

GEO Toolkit Updater

Pull the latest geo-seo-claude skills, agents, scripts, and schema templates from upstream, with a diff summary before anything is overwritten

5 minutes
Beginner
Developer Tools

Full-Output Enforcement: No Placeholders, No Stubs

A short rule set that bans TODO comments, skeleton code, and 'rest follows the same pattern' shortcuts so Claude always delivers complete, runnable output

2 minutes
Beginner
Developer Tools

GPT Taste Skill: Strict Anti-Slop UI Rules

A stricter, more deterministic anti-slop frontend ruleset with GSAP motion patterns, despite the GPT-oriented name it works as a standard CLAUDE.md in Claude Code

5 minutes
Intermediate
Developer Tools

GitHub Contributor

A phase-based playbook for shipping pull requests maintainers actually merge — discovery, CONTRIBUTING compliance, PR-size checks, minimal diffs, and post-submission interaction.

20 minutes
Intermediate
Developer Tools

GitHub Operations

Comprehensive GitHub operations using the gh CLI and REST/GraphQL APIs — PRs, issues, repositories, workflows, and bulk operations across public and Enterprise GitHub.

10 minutes
Intermediate
Developer Tools

Frontend Enhancer

Enhance Next.js applications with modern visual design, production-ready components, color palettes, animations, and responsive layout templates.

10 minutes
Intermediate
Developer Tools

Hookify Guardrails

Create custom Claude Code guardrails with lightweight markdown rule files instead of hand-editing hooks.json — pattern matching, no restart required, rules live-load on the next tool call.

5 minutes
Beginner

Browse all Developer Tools playbooks →