mcpField
U
ui-design

ui-design

github.com/arnavpuriDesign & UI17112 installsUpdated 5w ago
Repository

About ui-design

A UI design skill for developers covering components, layout, forms, responsive behavior, and accessibility. It advises loading project design context and checking rendered work with screenshots.

Key features

  1. 01Structure components with atomic design
  2. 02Define visual hierarchy and interaction states
  3. 03Cover navigation, forms, and feedback patterns
  4. 04Guide responsive and accessible design
  5. 05Verify rendered pages with screenshots

Use cases

  1. 01Plan page components and visual hierarchy
  2. 02Design forms and loading or error states
  3. 03Review mobile and desktop layouts

MCP support

When given a Figma URL, the instructions call for using Figma MCP tools get_design_context and get_screenshot to retrieve design context and screenshots.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/arnavpuri/designskills --skill ui-design

After installing, type/ui-designin Claude Code to confirm it loaded.

Details

From the project README

UI Design Patterns

Before You Start: Load Design Context

  1. Read .agents/design-context.md (written by the design-context skill). If it is missing, look for tokens in tailwind.config.* or :root CSS variables. If nothing exists, use the defaults (Primary #2563EB, Secondary #7C3AED, Accent #F59E0B, Tailwind gray neutrals, Inter for headings and body, Minimal style) and tell the user defaults were used — suggest running design-context.
  2. Map tokens to CSS variables once, then use only the variables: --color-primary, --color-primary-light, --color-primary-dark, --color-secondary, --color-accent, --color-neutral-50…--color-neutral-900, --color-success/-warning/-error, --font-heading, --font-body, --font-mono, --radius, and the 4px-base spacing scale.
  3. Tailwind: expose the same variables (v3 theme.extend, v4 @theme) as primary, primary-light, primary-dark, secondary, accent, neutral-*, font-heading, font-body. The indigo-* / gray-* classes in the examples below are placeholders for these tokens.
  4. Figma: if the user gives a Figma URL, pull it with the Figma MCP (get_design_context, get_screenshot) and match it; it overrides the context file for that design.
  5. Let the style archetype set radius, shadow depth, and how much of section 9 (trends) to use — Minimal and Corporate use none of it.

1. Component Design Principles (Atomic Design)

Build UI in layers. Never start with a full page — start with the smallest pieces.

Hierarchy
  1. Tokens — colors, spacing, radii, shadows, typography scale
  2. Atoms — button, input, badge, avatar, icon
  3. Molecules — search bar (input + button), form field (label + input + error), card header (avatar + name + timestamp)
  4. Organisms — navigation bar, hero section, comment thread, pricing table
  5. Templates — page layouts composed of organisms
  6. Pages — templates with real data
Rules
  • Every component gets its own set of CSS custom properties scoped to its root.
  • Prefer composition over configuration. A Card with children beats a Card with 15 props.
  • Components should be stateless by default. Lift state up.
/* Token layer — values come from .agents/design-context.md (defaults shown) */
:root {
  --color-primary: #2563EB;
  --color-surface: #FFFFFF;
  --radius-md: 0.75rem;
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.05);
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
}

Canonical spacing scale (all UI skills): 4px base — 4, 8, 12, 16, 24, 32, 48, 64px (Tailwind 1, 2, 3, 4, 6, 8, 12, 16). Don't use off-scale values.


2. Visual Hierarchy Framework

Control where the eye goes. Rank every element by importance and apply these levers:

LeverHigh EmphasisMedium EmphasisLow Emphasis
Size2rem+ heading1rem body0.75rem caption
Weight700–800 bold500 medium400 regular
ColorPrimary or high-contrast textMuted text (neutral-600)Subtle text (neutral-500 — lightest gray that still passes 4.5:1 on white)
SpacingMore whitespace around itStandard spacingTighter spacing
PositionTop-left or centerMid-pageBottom or sidebar
The Squint Test

Blur your eyes or zoom out to 25%. If you can still identify the primary action and main heading, your hierarchy works.

Tailwind Implementation
<!-- High emphasis -->
<h1 class="text-4xl font-extrabold tracking-tight text-gray-950">
  Ship faster with AI
</h1>

<!-- Medium emphasis -->
<p class="mt-4 text-lg text-gray-600 max-w-2xl">
  Build production-ready components in minutes, not hours.
</p>

<!-- Low emphasis -->
<span class="text-xs text-gray-500 uppercase tracking-wide">
  Updated 2 hours ago
</span>

3. Interactive States

Every interactive element needs all five states. No exceptions.

State Definitions
.btn-primary {
  /* Default */
  background: var(--color-primary);
  color: white;
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-4);
  font-weight: 600;
  transition: background-color 150ms ease, box-shadow 150ms ease, transform 150ms ease, filter 150ms ease;

  /* Hover — subtle lift or brightness shift */
  &:hover {
    filter: brightness(1.1);
    box-shadow: 0 4px 12px oklch(0% 0 0 / 0.15);
    transform: translateY(-1px);
  }

  /* Active — pressed feel */
  &:active {
    transform: translateY(0);
    filter: brightness(0.95);
    box-shadow: var(--shadow-sm);
  }

  /* Focus — visible ring for keyboard users */
  &:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
  }

  /* Disabled — dimmed, no hover/active effects (don't add pointer-events: none — it hides the not-allowed cursor) */
  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
    filter: none;
  }
}
Tailwind Shorthand
<button class="bg-indigo-600 text-white px-4 py-2 rounded-lg font-semibold
  hover:bg-indigo-500 hover:-translate-y-0.5 hover:shadow-lg
  active:translate-y-0 active:bg-indigo-700
  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600
  disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
  transition-all duration-150">
  Click me
</button>

4. Feedback Patterns

Loading States
  • Skeleton screens over spinners. Show the shape of content that's coming.
  • Use motion-safe:animate-pulse on placeholder blocks, and mark the region aria-busy="true" with an sr-only "Loading…" label.
  • Show loading inline near the action that triggered it.
<!-- Skeleton card -->
<div class="motion-safe:animate-pulse space-y-3" aria-busy="true">
  <span class="sr-only">Loading…</span>
  <div class="h-48 bg-gray-200 rounded-xl"></div>
  <div class="h-4 bg-gray-200 rounded w-3/4"></div>
  <div class="h-4 bg-gray-200 rounded w-1/2"></div>
</div>
Success State
  • Green accent, checkmark icon, brief confirmation text.
  • Announce it with role="status" (polite live region). Auto-dismiss after 5+ seconds, and never auto-dismiss messages that contain an action.
Error State
  • Red accent, descriptive message, recovery action.
  • Never just say "Error." Say what went wrong and what to do.
  • Don't rely on red alone: pair it with an icon and text; use role="alert" for errors that appear after submit.
Empty State
  • Illustration or icon, explanation, primary action to fix it.
<div class="text-center py-16">
  <svg class="mx-auto h-12 w-12 text-gray-400" aria-hidden="true"><!-- inbox icon --></svg>
  <h3 class="mt-4 text-lg font-semibold text-gray-900">No messages yet</h3>
  <p class="mt-2 text-sm text-gray-500">Start a conversation to see messages here.</p>
  <button type="button" class="mt-6 bg-indigo-600 text-white px-4 py-2 rounded-lg">
    New message
  </button>
</div>

5. Navigation Patterns

Sidebar Navigation
  • Width: 240–280px desktop, collapsible to 64px (icon-only).
  • Group items by category with subtle section headers.
  • Active item: filled background, bold text, left accent bar, and aria-current="page".
Top Navigation
  • Fixed/sticky at top. Height: 56–64px.
  • Logo left, nav links center or left, actions right.
  • Mobile: collapse to hamburger at md breakpoint.
Tabs
  • Use for switching views within the same context.
  • Active tab: bottom border (2–3px) in primary color + bold text. Use role="tablist"/role="tab" with aria-selected and arrow-key navigation (or plain links if each tab is its own URL).
  • Never more than 7 tabs. Use dropdown overflow for more.
Breadcrumbs
  • Use / or > separator.
  • Current page is not a link, just text.
  • Truncate middle items on long paths.

6. Form Design

Rules
  1. Labels above inputs — not floating, not inline. Always visible.
  2. One column — multi-column forms reduce completion rate.
  3. Group related fields with subtle section dividers.
  4. Inline validation — validate on blur, not on every keystroke.
  5. Error messages below the field, in red, with specific guidance.
  6. Primary action left-aligned at form bottom. Secondary action as text link.
<div class="space-y-1.5">
  <label for="email" class="block text-sm font-medium text-gray-700">
    Email address
  </label>
  <input
    type="email"
    id="email"
    class="block w-full rounded-lg border border-gray-300 px-3 py-2
      text-gray-900 placeholder:text-gray-400
      focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20
      transition-colors"
    placeholder="[email protected]"
    autocomplete="email"
    aria-describedby="email-error"
  />
  <!-- On error: remove `hidden` and set aria-invalid="true" on the input -->
  <p id="email-error" class="text-sm text-red-600 hidden">Please enter a valid email address.</p>
</div>

7. Accessibility as Design

Accessibility is not an afterthought. It is a design constraint applied from the start.

Contrast
  • Normal text: 4.5:1 minimum contrast ratio (WCAG 2.2 AA).
  • Large text (≥24px regular, or ≥18.66px bold): 3:1 minimum.
  • Non-text UI (input borders, icons, focus rings, chart marks): 3:1 against adjacent colors.
  • Placeholder text is not a label and should still meet 4.5:1 if it carries information.
  • Use oklch color space for perceptually uniform contrast adjustments.
Focus Indicators
  • Never remove outline without replacing it.
  • Use focus-visible (not focus) to avoid showing rings on mouse click.
  • Ring: 2px solid, offset 2px, primary color, with 3:1 contrast against the background.
  • Focused elements must not be hidden behind sticky headers/footers (WCAG 2.4.11) — add scroll-padding-top equal to the header height.
Target Size
  • WCAG 2.5.8 (AA): pointer targets at least 24×24 CSS px (or spaced so a 24px circle doesn't overlap a neighbour).
  • Platform guidance for touch: 44×44pt (Apple HIG), 48×48dp (Material). Use 44px+ for primary touch targets.
Semantic Structure
  • One <h1> per page.
  • Headings in order (h1 > h2 > h3). Never skip levels.
  • Use <nav>, <main>, <aside>, <footer> landmarks.
  • Buttons for actions, links for navigation. Never <div onclick>.
  • aria-label on icon-only buttons.
Motion
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

8. Responsive Breakpoint Strategy

Breakpoints (Tailwind defaults — canonical for all UI skills)
NameWidthTarget
sm640pxLarge phones landscape
md768pxTablets
lg1024pxSmall laptops
xl1280pxDesktops
2xl1536pxLarge screens
Mobile-First Rules
  • Start with the mobile layout. Add complexity at larger breakpoints.
  • Stack columns on mobile, side-by-side on md+.
  • Navigation becomes hamburger below md.
  • Font sizes scale up: text-2xl md:text-4xl lg:text-5xl.
  • Generous touch padding on mobile: p-4, tighten on desktop: lg:p-2.
Container Queries (Modern CSS)
.card-container {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

9. Modern UI Trends

Glassmorphism
.glass {
  background: oklch(100% 0 0 / 0.1);
  backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid oklch(100% 0 0 / 0.15);
  border-radius: 1rem;
}

Glass only works over a busy background — check text contrast against the lightest area behind it, and give a solid fallback: @supports not (backdrop-filter: blur(1px)) { .glass { background: oklch(20% 0.02 265 / 0.9); } }.

Bento Grid
.bento {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(200px, auto); /* fixed 200px rows clip long content */
  gap: 1rem;
}
@media (max-width: 767px) { .bento { grid-template-columns: 1fr; } .bento .featured { grid-column: auto; grid-row: auto; } }
.bento .featured {
  grid-column: span 2;
  grid-row: span 2;
}
Aurora / Mesh Gradient Background
.aurora {
  background: linear-gradient(135deg, oklch(85% 0.15 280), oklch(80% 0.2 320), oklch(75% 0.18 200));
  background-size: 400% 400%;
  animation: aurora-shift 8s ease infinite;
}
@keyframes aurora-shift {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}

10. Advanced CSS Techniques

:has() — Parent Selector
/* Highlight form group when input is focused */
.form-group:has(input:focus-visible) {
  background: oklch(97% 0.01 265);
  border-color: var(--color-primary);
}

/* Card changes layout when it contains an image */
.card:has(img) {
  grid-template-rows: 200px 1fr;
}
Subgrid
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}
.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3; /* header, body, footer align across cards */
}
Scroll-Driven Animations
/* Progressive enhancement: only where supported and motion is OK */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .fade-in {
      animation: fade-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 100%;
    }
  }
}
@keyframes fade-in {
  from { opacity: 0; transform: translateY(2rem); }
  to { opacity: 1; transform: translateY(0); }
}

Verify: Render and Check

Don't hand over code you haven't looked at. After generating it:

  1. Screenshot it at mobile and desktop widths, e.g. npx playwright screenshot --full-page --viewport-size=390,844 file://$PWD/index.html mobile.png, then again with --viewport-size=1440,900 (or point at the dev server URL).
  2. Open both images and check: no horizontal scroll or clipped/overlapping text, hierarchy reads at a glance, brand tokens are applied, images load at the right aspect ratio.
  3. Tab through once: every interactive element gets a visible focus ring, in a logical order.
  4. Check every state you built (hover, focus, disabled, loading, empty, error) at least once, and run a contrast check on muted text.
  5. Fix what you find and re-screenshot before reporting done.

Quick Reference: Design Checklist

Before shipping any UI component, verify:

  • Visual hierarchy is clear (squint test passes)
  • All interactive elements have hover, active, focus-visible, and disabled states
  • Color contrast meets WCAG 2.2 AA (4.5:1 text, 3:1 large text and UI components)
  • Targets are ≥24×24px (44px+ for primary touch targets)
  • Rendered and screenshotted at 390px and 1440px (see Verify)
  • Focus order is logical (tab through the page)
  • Responsive at all breakpoints (320px to 1920px)
  • Loading, empty, and error states are designed
  • Spacing uses the 4px-base scale (4, 8, 12, 16, 24, 32, 48, 64)
  • Typography scale is limited to 4–6 sizes
  • Motion respects prefers-reduced-motion
  • Semantic HTML is used (landmarks, headings, button vs. link)

Comments

Markdown supported