ui-patterns

SKILL.md

UI Patterns

Required: Dark Mode Support

All UI components MUST support dark mode using Tailwind's class strategy.

// Always provide dark: variants
className="bg-white dark:bg-slate-900 text-slate-900 dark:text-white"

Color System

Brand Colors (Blue) - Primary actions

  • brand-500 / brand-600 - Primary buttons, links
  • brand-100 / dark:brand-900/30 - Highlighted backgrounds
  • brand-700 / dark:brand-300 - Text on brand backgrounds

System Colors (Slate) - UI chrome

  • slate-50 / dark:slate-950 - Page backgrounds
  • slate-100 / dark:slate-800 - Secondary/card backgrounds
  • slate-200 / dark:slate-700 - Borders
  • slate-400 - Muted text
  • slate-700 / dark:white - Primary text

Semantic Colors

  • Success: emerald-* (done, approved)
  • Warning: amber-* (pending, paused)
  • Error: red-* (failed, stopped)

Component Classes

Use pre-defined component classes for consistency:

// Buttons
<button className="btn btn-primary">Create</button>
<button className="btn btn-secondary">Cancel</button>
<button className="btn btn-ghost">Refresh</button>
<button className="btn btn-danger">Delete</button>

// Inputs
<input className="input" />
<textarea className="input resize-none" />

// Select dropdowns
<select className="select w-[180px]">
  <option>Option</option>
</select>

// Cards
<div className="card p-4">Content</div>

Status Badges

Use consistent status badge pattern with icons:

const STATUS_CONFIG = {
  backlog: { icon: "inbox", classes: "bg-slate-100 text-slate-700 border-slate-200 dark:bg-slate-800 dark:text-slate-300 dark:border-slate-700" },
  ready: { icon: "circle-dashed", classes: "bg-slate-100 text-slate-700 border-slate-200 dark:bg-slate-800 dark:text-slate-300 dark:border-slate-700" },
  in_progress: { icon: "timer", classes: "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-800" },
  pending_review: { icon: "eye", classes: "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800" },
  done: { icon: "check-circle", classes: "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800" },
};

// Badge structure
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium border whitespace-nowrap {classes}">
  <Icon className="w-3.5 h-3.5" />
  {label}
</span>

Typography

// Page titles
<h1 className="text-2xl font-semibold text-slate-900 dark:text-white">

// Section titles
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">

// Subsection headers (uppercase)
<h3 className="text-xs font-bold text-slate-400 uppercase tracking-wider">

Layout Patterns

Split Pane (50/50)

<div className="flex flex-1 min-h-0 overflow-hidden rounded-lg border border-slate-200 dark:border-slate-800">
  <div className="w-1/2 border-r border-slate-200 dark:border-slate-800 p-6 overflow-y-auto bg-white dark:bg-slate-900">
    {/* Left panel */}
  </div>
  <div className="w-1/2 flex flex-col min-w-0">
    {/* Right panel */}
  </div>
</div>

Section Card

<div className="p-4 bg-slate-50 dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700">
  <h3 className="text-sm font-medium text-slate-900 dark:text-white mb-3">
    Section Title
  </h3>
  {/* Content */}
</div>

Modal Pattern

<div className="fixed inset-0 z-50 flex items-center justify-center">
  <div className="absolute inset-0 bg-black/50" onClick={onClose} />
  <div className="relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-full max-w-lg mx-4 border border-slate-200 dark:border-slate-700">
    {/* Header */}
    <div className="flex items-center justify-between px-6 py-4 border-b border-slate-200 dark:border-slate-700">
      <h2 className="text-lg font-semibold text-slate-900 dark:text-white">Title</h2>
      <button onClick={onClose}>...</button>
    </div>
    {/* Body */}
    <div className="px-6 py-4">...</div>
    {/* Footer */}
    <div className="flex items-center justify-end gap-3 px-6 py-4 border-t border-slate-200 dark:border-slate-700">
      <button className="btn btn-secondary">Cancel</button>
      <button className="btn btn-primary">Submit</button>
    </div>
  </div>
</div>

Spacing Guidelines

Size Usage
gap-1.5 Icon + text in badges
gap-2 Button groups
gap-3 Form fields
gap-4 Section spacing
gap-6 Major section spacing
p-4 Card padding
p-6 Modal/panel padding

Scrollbars

Use .scrollbar-thin for custom scrollbars:

<div className="overflow-y-auto scrollbar-thin">

Loading States

// Skeleton loader
<div className="animate-pulse bg-slate-200 dark:bg-slate-700 rounded h-4 w-32" />

// Spinner
<svg className="animate-spin h-5 w-5 text-blue-500" viewBox="0 0 24 24">
  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>

Empty States

<div className="flex flex-col items-center justify-center py-12 text-center">
  <Icon className="w-12 h-12 text-slate-300 dark:text-slate-600 mb-4" />
  <h3 className="text-lg font-medium text-slate-900 dark:text-white mb-2">
    No items found
  </h3>
  <p className="text-sm text-slate-500 dark:text-slate-400 mb-4">
    Get started by creating your first item.
  </p>
  <button className="btn btn-primary">Create Item</button>
</div>
Weekly Installs
5
GitHub Stars
7
First Seen
Jan 24, 2026
Installed on
cursor5
claude-code4
github-copilot4
opencode4
trae3
gemini-cli3