src/bmm-skills/2-plan-workflows/bmad-ux/assets/experience-example-shadcn.md
Illustrative example. Single-surface responsive web. shadcn/ui on Next.js + Tailwind. Paired with
design-example-shadcn.md(Drift DESIGN.md). Demonstrates: component-library inheritance, keyboard-first interaction primitives, the "shadcn + brand-layer" pattern that covers most modern web SaaS.
Single-surface responsive web. shadcn/ui on Next.js 15+ with Tailwind CSS. The component library does most of the work; brand discipline is "respect the defaults except where the brand layer overrides them." DESIGN.md is the visual identity reference and names the override surface; this spine is the experience. Single-tenant per project; users can belong to multiple projects but each project is a self-contained workspace.
| Surface | Reached from | Purpose |
|---|---|---|
| Today | App open / g t | Current focus, in-progress tasks pulled from all projects |
| Projects | Sidebar / g p | List of active and archived projects |
| Project detail | Projects row / g 1–g 9 | Tasks in this project, organized by lane |
| Search | ⌘K / Ctrl+K | Command palette — surface, navigate, act |
| Settings | Avatar menu | Account, theme, keyboard shortcuts, billing |
Sidebar collapses to icons on md; becomes a Sheet on sm. Modal stacks one level deep (e.g., open Dialog on top of a surface, never on top of another dialog).
→ Composition reference: mockups/today.html, mockups/project-detail.html, mockups/command-palette.html. Spine wins on conflict.
Microcopy. Brand voice and aesthetic posture live in DESIGN.md.
| Do | Don't |
|---|---|
| "What are you working on?" | "Let's get productive! 🚀" |
| "3 tasks in motion" | "You have 3 active items." |
| "Closed. Nice work." | "Task completed successfully ✓" |
| "Nothing in motion. Pick something." | "No active tasks. Click below to get started!" |
| Manager-facing: counts and verbs. Employee-facing: same. | Different tone per audience — Drift talks to everyone the same way. |
Behavioral. Visual specs live in DESIGN.md.Components (or in shadcn defaults, when inherited).
| Component | Use | Behavioral rules |
|---|---|---|
| Task row | Projects, Today | Click anywhere on row opens edit dialog. Checkbox toggles done state with optimistic update. Hover reveals quick-actions (focus, defer, archive). |
| Focus card | Today, Project detail | At most one focus card per surface — the task or project marked with focus state. f keyboard shortcut sets focus on the active row. |
| Command palette | Global (⌘K) | Fuzzy search across all projects, tasks, and commands. Enter fires the highlighted result. → previews a result. Escape closes. |
| Project header | Project detail | Inline-editable title (click to edit, blur to save). Status pill: active / archived / done. |
| Empty state | Anywhere | shadcn's empty pattern + one Drift-specific sentence. display-sm for the headline, body text below, single primary action. |
| State | Surface | Treatment |
|---|---|---|
| Cold app load | Today | shadcn Skeleton rows (4-6) match expected layout. Resolves on data. |
| No focus | Today | display-sm: "Nothing in motion. Pick something." Below: list of in-progress tasks from all projects. |
| Empty project | Project detail | display-sm: "{Project title} is empty." Body: "Add a first task to get going." Single primary button. |
| Command palette no matches | ⌘K | "No matches. Start typing a task or project name, or pick an action below." Followed by 4-5 common commands. |
| Offline | Global (status bar) | shadcn Toast once: "You're offline. Changes will sync when you reconnect." Local writes continue. |
| Permission denied | Projects (others' private) | Surface hidden from sidebar. No "blocked" screen. |
| Stale data | Project detail | If background refresh detects changes, shadcn Toast: "Updated by {user_name}. Refresh." Manual refresh, no auto. |
Keyboard-first. Drift's primary audience is developers and power users; the keyboard surface is the product, the mouse is fallback.
⌘K / Ctrl+K — Command palette (universal)g t / g p — Go to Today / Projects (vim-style)g 1–g 9 — Go to project by sidebar positionf — Set focus on highlighted task/projectc — Create new task (context-aware: in the active project)Esc — Close dialogs, exit edit mode, clear command palette/ — Focus search in current surfaceMouse: click to act, drag deferred to v2. Hover reveals row actions on md+ (touch users tap to reveal).
Banned everywhere: infinite scroll (pagination only), drag-to-reorder in v1, hover-only affordances on sm viewports, modal stacks > 1 level deep.
Behavioral. Visual contrast lives in DESIGN.md (inherits shadcn's WCAG AA-compliant defaults; brand overrides verified to maintain ratios).
g t etc.) — users with motor-control limitations get the same surface as power users.Tab order matches reading order on every surface. Esc always closes the topmost modal/popover.aria-live.ring token — visible at AA contrast against background.| Breakpoint | Behavior |
|---|---|
≥ lg (1024px+) | Sidebar visible. Today is a 2-column layout: focus + in-motion list. |
md (768–1023px) | Sidebar collapses to icons. Today stacks to single column. |
< md (sm) | Sidebar becomes a Sheet triggered from top bar. Command palette opens fullscreen. |
Drift is responsive web, not a native mobile app. The product works on phones for read + simple-edit, but the primary surface is desktop / laptop.
⌘K is the command center; vim-style nav (g t); no drag for primary navigation; status pill vocabulary.display-sm: "Welcome back, Sarah." Focus card shows yesterday's marked task — "Finish landing page hero copy" — still in motion.⌘K, types "ship hero", sees the matching task and presses Enter to open it.Failure: data save fails → shadcn Toast (destructive variant): "Couldn't save. Trying again." Inline edit retained; another Enter retries.
done.f on the row to mark it as her focus, then Enter to open it.⌘K defaults its first result to "Go to Auth project." The state of the team's progress is embedded in her surface — no Slack thread to scroll, no status doc to read.Failure: Devon hadn't actually assigned the follow-up — Mara mis-assigned to herself. She hits Esc, f again to unfocus, and reassigns to Devon. No "are you sure" dialog; Drift trusts the user.