ui-design
Core UI patterns for components and app screens: tokens, visual hierarchy, interactive states, forms, navigation, feedback states, accessibility, and responsive rules. Use when the user asks to "design a UI", "build a component", "create an interface", "style a form", "make it look good", "improve the design", "add hover states", "make it accessible", or any general UI work. This is the base the other UI skills build on; prefer landing-page-design for full marketing pages, hero-section for only the above-the-fold block, card-design for cards, dashboard-design for data-dense admin views, mobile-ui-design for touch-first screens, dark-mode for theming, and email-design for HTML email.
How do I install this agent skill?
npx skills add https://github.com/arnavpuri/designskills --skill ui-designIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill provides comprehensive UI design patterns and instructions. It includes a verification step that uses the Playwright tool to take screenshots of the generated UI for quality assurance. The skill also allows for importing design tokens and hierarchy from local configuration files or external Figma URLs. The security review identifies the use of shell commands and the ingestion of external design data as potential risk factors for indirect prompt injection.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 1 issue
What does this agent skill do?
UI Design Patterns
Before You Start: Load Design Context
- Read
.agents/design-context.md(written by thedesign-contextskill). If it is missing, look for tokens intailwind.config.*or:rootCSS 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 runningdesign-context. - 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. - Tailwind: expose the same variables (v3
theme.extend, v4@theme) asprimary,primary-light,primary-dark,secondary,accent,neutral-*,font-heading,font-body. Theindigo-*/gray-*classes in the examples below are placeholders for these tokens. - 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. - 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
- Tokens — colors, spacing, radii, shadows, typography scale
- Atoms — button, input, badge, avatar, icon
- Molecules — search bar (input + button), form field (label + input + error), card header (avatar + name + timestamp)
- Organisms — navigation bar, hero section, comment thread, pricing table
- Templates — page layouts composed of organisms
- 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
Cardwithchildrenbeats aCardwith 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:
| Lever | High Emphasis | Medium Emphasis | Low Emphasis |
|---|---|---|---|
| Size | 2rem+ heading | 1rem body | 0.75rem caption |
| Weight | 700–800 bold | 500 medium | 400 regular |
| Color | Primary or high-contrast text | Muted text (neutral-600) | Subtle text (neutral-500 — lightest gray that still passes 4.5:1 on white) |
| Spacing | More whitespace around it | Standard spacing | Tighter spacing |
| Position | Top-left or center | Mid-page | Bottom 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-pulseon placeholder blocks, and mark the regionaria-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
mdbreakpoint.
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"witharia-selectedand 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
- Labels above inputs — not floating, not inline. Always visible.
- One column — multi-column forms reduce completion rate.
- Group related fields with subtle section dividers.
- Inline validation — validate on blur, not on every keystroke.
- Error messages below the field, in red, with specific guidance.
- 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="you@example.com"
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
outlinewithout replacing it. - Use
focus-visible(notfocus) 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-topequal 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-labelon 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)
| Name | Width | Target |
|---|---|---|
sm | 640px | Large phones landscape |
md | 768px | Tablets |
lg | 1024px | Small laptops |
xl | 1280px | Desktops |
2xl | 1536px | Large 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:
- 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). - 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.
- Tab through once: every interactive element gets a visible focus ring, in a logical order.
- Check every state you built (hover, focus, disabled, loading, empty, error) at least once, and run a contrast check on muted text.
- 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)
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/arnavpuri/designskills/ui-design">View ui-design on skillZs</a>