whale-igniter 1.2.3 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +19 -2
  2. package/dist/analyzer/insights.js +144 -0
  3. package/dist/commands/adopt.js +20 -0
  4. package/dist/commands/changes.js +127 -0
  5. package/dist/commands/ignite.js +142 -76
  6. package/dist/commands/insights.js +146 -9
  7. package/dist/commands/references.js +193 -0
  8. package/dist/commands/sync.js +8 -0
  9. package/dist/generators/wikiGenerator.js +8 -304
  10. package/dist/index.js +33 -2
  11. package/dist/mcp/server.js +29 -0
  12. package/dist/scanner/extractors/css.js +95 -0
  13. package/dist/scanner/extractors/inline.js +131 -0
  14. package/dist/scanner/extractors/styleBlocks.js +37 -0
  15. package/dist/scanner/normalizer.js +59 -0
  16. package/dist/scanner/tailwindScanner.js +39 -0
  17. package/dist/templates/claude.js +93 -0
  18. package/dist/templates/components.js +45 -0
  19. package/dist/templates/conventions.js +45 -0
  20. package/dist/templates/decisions.js +34 -0
  21. package/dist/templates/foundations.js +34 -0
  22. package/dist/templates/project.js +82 -0
  23. package/dist/utils/aiAvailability.js +25 -0
  24. package/dist/utils/wizardMapping.js +54 -0
  25. package/dist/version.js +1 -1
  26. package/package.json +4 -2
  27. package/packs/atlas/instructions.md +3 -0
  28. package/packs/atlas/manifest.json +8 -0
  29. package/packs/atlas/rules.md +4 -0
  30. package/packs/forge/instructions.md +3 -0
  31. package/packs/forge/manifest.json +8 -0
  32. package/packs/forge/rules.md +4 -0
  33. package/packs/lighthouse/instructions.md +3 -0
  34. package/packs/lighthouse/manifest.json +8 -0
  35. package/packs/lighthouse/rules.md +4 -0
  36. package/packs/scribe/instructions.md +3 -0
  37. package/packs/scribe/manifest.json +8 -0
  38. package/packs/scribe/rules.md +4 -0
  39. package/packs/selene/instructions.md +3 -0
  40. package/packs/selene/manifest.json +7 -0
  41. package/packs/selene/rules.md +4 -0
  42. package/ui-references/INDEX.md +51 -0
  43. package/ui-references/data-display.md +160 -0
  44. package/ui-references/feedback.md +190 -0
  45. package/ui-references/forms.md +192 -0
  46. package/ui-references/layout.md +155 -0
  47. package/ui-references/navigation.md +188 -0
  48. package/ui-references/surface.md +188 -0
@@ -0,0 +1,155 @@
1
+ # Layout — UI References
2
+
3
+ Layout components and patterns define how content is positioned, sized, and reflowed across viewports. They are the invisible scaffolding of every screen. Good layout is invisible — content feels natural and reachable. Bad layout manifests as content that overflows on mobile, pages that don't scale, or sidebar panels that get in the way.
4
+
5
+ ---
6
+
7
+ ## Container
8
+
9
+ A centered, width-constrained wrapper that gives content a comfortable reading width and consistent horizontal margins. The outermost structural element on most pages.
10
+
11
+ ### Reference implementations
12
+
13
+ - **[Vercel/Geist Container](https://vercel.com/geist/container)** — `max-width` variants (sm, md, lg, xl), centered with `margin: 0 auto`, horizontal padding that scales with viewport width. The pattern to copy for most web apps.
14
+ - **[Tailwind CSS Container](https://tailwindcss.com/docs/container)** — `container` class with `mx-auto` and responsive padding; a widely-used baseline.
15
+
16
+ ### Minimum quality bar
17
+
18
+ - [ ] Maximum width is appropriate for the content type (prose: 65–75ch; app UI: 1280px)
19
+ - [ ] Horizontal padding on both sides that scales with viewport — at minimum 16px on mobile, 24–32px on desktop
20
+ - [ ] Centers with `margin: 0 auto` — never with absolute positioning
21
+ - [ ] Does not constrain child elements from filling their parent width
22
+ - [ ] Nested containers: inner containers should not re-apply the outer max-width
23
+
24
+ ### Common mistakes
25
+
26
+ - Using 100vw for the container width — includes scrollbar width and causes horizontal overflow on Windows
27
+ - Container with no horizontal padding on mobile — content touches viewport edges
28
+ - Nesting full-width sections inside a container that then applies max-width to everything
29
+
30
+ ---
31
+
32
+ ## Stack
33
+
34
+ A one-dimensional layout that distributes children along a single axis (vertical or horizontal) with consistent spacing. The most frequent layout primitive.
35
+
36
+ ### Reference implementations
37
+
38
+ - **[Every Layout — Stack](https://every-layout.dev/layouts/stack/)** — the canonical primitive: each child separated by a consistent gap, no global margin reset needed.
39
+ - **[Radix UI Flex](https://www.radix-ui.com/themes/docs/layout/flex)** — flex-based stack with `gap`, `direction`, `align`, `justify` props; useful as a design system primitive.
40
+ - **[Tailwind's flex/gap utilities](https://tailwindcss.com/docs/display#flex)** — `flex flex-col gap-4` is the practical implementation of a vertical stack in Tailwind.
41
+
42
+ ### Minimum quality bar
43
+
44
+ - [ ] Spacing between children uses `gap`, not margin on individual children — `gap` does not collapse and doesn't affect the outermost children
45
+ - [ ] Direction is explicit: vertical stack uses `flex-col`; horizontal uses `flex-row`
46
+ - [ ] Wrapping behavior is explicit: decide whether children wrap to the next row or clip
47
+ - [ ] Alignment: cross-axis alignment (`align-items`) defaults to `stretch` — be intentional about changing it
48
+ - [ ] Nested stacks use their own `gap` — do not inherit from a parent
49
+
50
+ ### Common mistakes
51
+
52
+ - Using margin-bottom on children for spacing — breaks the last-child, creates double margins when nesting
53
+ - Gap on a non-flex/non-grid element — `gap` only works on flex and grid containers
54
+ - Using negative margin to "fix" unwanted spacing from margins — indicates a structural problem, not a spacing one
55
+
56
+ ---
57
+
58
+ ## Grid
59
+
60
+ A two-dimensional layout for aligning content in rows and columns. Use for card grids, form field layouts, and any content that requires both row and column alignment.
61
+
62
+ ### Reference implementations
63
+
64
+ - **[Every Layout — Grid](https://every-layout.dev/layouts/grid/)** — the auto-fill/minmax pattern for responsive grids that reflow without breakpoints; the right default for card grids.
65
+ - **[CSS Grid by Example](https://gridbyexample.com/)** — Rachel Andrew's reference; authoritative for advanced grid patterns.
66
+ - **[Radix UI Grid](https://www.radix-ui.com/themes/docs/layout/grid)** — a grid primitive with explicit `columns` prop for column count control.
67
+
68
+ ### Minimum quality bar
69
+
70
+ - [ ] Responsive: use `auto-fill` or `auto-fit` with `minmax()` for self-reflowing grids; explicit breakpoints for controlled column counts
71
+ - [ ] Gutters use `gap`, not margin — ensures equal spacing horizontally and vertically
72
+ - [ ] Items in the same row are the same height by default (CSS Grid stretches to match the tallest item)
73
+ - [ ] Named grid areas for complex layouts: makes the layout intent readable in code
74
+
75
+ ### Common mistakes
76
+
77
+ - Using `float` or `inline-block` for grid layouts — no longer appropriate; use Grid or Flexbox
78
+ - Fixed-width columns that don't reflow — always pair fixed-width grids with `overflow-x: auto` or responsive breakpoints
79
+ - `auto-fit` vs `auto-fill` confusion: `auto-fit` collapses empty tracks (items stretch); `auto-fill` preserves empty column tracks
80
+
81
+ ---
82
+
83
+ ## Responsive Patterns
84
+
85
+ Strategies for adapting layout to different viewport widths. Not a component, but a set of decisions that every component must make.
86
+
87
+ ### Reference implementations
88
+
89
+ - **[Every Layout](https://every-layout.dev/)** — the complete reference for responsive layout primitives (Stack, Box, Center, Cluster, Sidebar, Switcher, Cover, Grid, Frame, Reel, Imposter, Icon). These patterns cover 95% of layout needs without breakpoints.
90
+ - **[Tailwind responsive prefixes](https://tailwindcss.com/docs/responsive-design)** — `sm:`, `md:`, `lg:`, `xl:` breakpoints for when intrinsic layouts are insufficient.
91
+
92
+ ### Minimum quality bar
93
+
94
+ - [ ] Mobile-first: default styles are for small viewports; larger-viewport styles override with `@media (min-width: ...)`
95
+ - [ ] No horizontal scroll on any viewport wider than 320px
96
+ - [ ] Touch targets minimum 44×44px on all interactive elements
97
+ - [ ] Text never smaller than 16px on mobile (prevents browser auto-zoom on iOS)
98
+ - [ ] Images and media use `max-width: 100%` and `height: auto` — never overflow their container
99
+ - [ ] Test at: 320px (smallest iPhone SE), 390px (iPhone 14), 768px (tablet), 1440px (desktop)
100
+
101
+ ### Common mistakes
102
+
103
+ - Desktop-first design that patches mobile with `max-width` overrides — creates specificity battles
104
+ - Layout that assumes a specific viewport height — mobile browsers have variable chrome heights
105
+ - `vw` units for font size — creates tiny text on narrow viewports and huge text on wide ones; use `clamp()` for fluid typography
106
+
107
+ ---
108
+
109
+ ## Sidebar Layout
110
+
111
+ A two-column layout with a persistent sidebar (navigation or contextual content) and a main content area. The most common structure for application dashboards.
112
+
113
+ ### Reference implementations
114
+
115
+ - **[shadcn/ui Sidebar](https://ui.shadcn.com/docs/components/sidebar)** — comprehensive implementation: collapsible, icon-only mode, mobile sheet overlay, keyboard navigation, persistent open/closed state.
116
+ - **[Linear's layout](https://linear.app)** — observe: resizable sidebar, persistent state across reloads, collapses to icon-only at narrower widths, slides away on mobile.
117
+ - **[Radix UI layout primitives](https://www.radix-ui.com/themes/docs/layout/box)** — Box and Flex for building custom sidebar layouts.
118
+
119
+ ### Minimum quality bar
120
+
121
+ - [ ] Sidebar width is either fixed or resizable within a min/max range
122
+ - [ ] Sidebar open/closed state persists across navigation (local storage or cookie)
123
+ - [ ] Mobile: sidebar slides off-screen; toggle button always visible; opens as overlay, not by pushing content
124
+ - [ ] Main content area uses `min-width: 0` to allow flex children to shrink below content size
125
+ - [ ] Keyboard: pressing a sidebar nav item moves focus into the main content area
126
+ - [ ] Skip-to-content link at page top jumps past the sidebar for keyboard users
127
+
128
+ ### Common mistakes
129
+
130
+ - Sidebar with `overflow: hidden` — clips content and breaks dropdown menus that extend beyond the sidebar
131
+ - Sidebar that pushes content off-screen on resize — use CSS variables for width so transitions stay smooth
132
+ - Mobile sidebar that requires a hard page navigation to close — use an overlay and an `×` button
133
+
134
+ ---
135
+
136
+ ## Cluster / Inline Group
137
+
138
+ A horizontal group of items that wraps to the next line when the container is too narrow. Common for button groups, tag collections, filter chips, and navigation items.
139
+
140
+ ### Reference implementations
141
+
142
+ - **[Every Layout — Cluster](https://every-layout.dev/layouts/cluster/)** — `flex-wrap: wrap` with `gap` is the complete pattern; no media queries needed.
143
+ - **[Tailwind flex-wrap](https://tailwindcss.com/docs/flex-wrap)** — `flex flex-wrap gap-2` covers most cluster needs.
144
+
145
+ ### Minimum quality bar
146
+
147
+ - [ ] `flex-wrap: wrap` so items reflow naturally rather than overflowing
148
+ - [ ] `gap` (not margin) between items so wrapping rows also have vertical spacing
149
+ - [ ] Alignment: `align-items: center` for mixed-height items (icon + text, badges + text)
150
+ - [ ] When items must not wrap: `overflow-x: auto` with `-webkit-overflow-scrolling: touch` for mobile swipe
151
+
152
+ ### Common mistakes
153
+
154
+ - Cluster with margin-right on children but no margin on the last item — creates right overhang
155
+ - Mixing margin and gap for spacing in the same container — pick one
@@ -0,0 +1,188 @@
1
+ # Navigation — UI References
2
+
3
+ Navigation elements help users understand where they are and move confidently through an application. Poor navigation is one of the top reasons users abandon software. Good navigation is invisible: users find what they need without thinking about the mechanism.
4
+
5
+ ---
6
+
7
+ ## Navigation Bar
8
+
9
+ The persistent top bar that identifies the application and provides access to primary destinations. It must be consistent across all screens and never disappear unexpectedly.
10
+
11
+ ### Reference implementations
12
+
13
+ - **[Linear's top nav](https://linear.app)** — observe in the app: no wordmark at scale (icon only), workspace switcher, command bar in center, user avatar at far right. Extremely low visual weight — chrome stays out of the way of content.
14
+ - **[Vercel/Geist Header](https://vercel.com/geist/components)** — persistent nav with responsive collapse to hamburger on mobile; good reference for how a complex nav simplifies at small breakpoints.
15
+ - **[GitHub Primer Global Nav](https://primer.style/components/nav-list/react/alpha)** — handles authenticated vs. unauthenticated states, notification badge, and global search without cluttering the bar.
16
+ - **[Atlassian Navigation](https://atlassian.design/components/atlassian-navigation/examples)** — horizontal nav for complex products with overflow handling when items don't fit.
17
+
18
+ ### Minimum quality bar
19
+
20
+ - [ ] `<nav>` element with `aria-label="Main"` (distinguish from secondary navs on the page)
21
+ - [ ] Current page/section has `aria-current="page"` on its link
22
+ - [ ] Keyboard: all links reachable by Tab; no keyboard traps
23
+ - [ ] Mobile: all destinations accessible (not hidden behind a broken hamburger)
24
+ - [ ] Logo links to home; clicking it from home does not reload the page in a disorienting way
25
+ - [ ] Skip navigation link is the first focusable element on the page
26
+
27
+ ### Common mistakes
28
+
29
+ - Multiple `<nav role="navigation">` without distinct `aria-label` — screen readers can't distinguish them
30
+ - Hiding the hamburger menu without a visible open state indicator
31
+ - Nav items that look like buttons but navigate — use `<a>`, not `<button>`
32
+
33
+ ---
34
+
35
+ ## Tabs
36
+
37
+ Tabs switch between views of the same conceptual space. The content area changes; the URL may or may not change depending on whether tabs represent distinct routes.
38
+
39
+ ### Reference implementations
40
+
41
+ - **[Radix UI Tabs](https://www.radix-ui.com/primitives/docs/components/tabs)** — the correct `tablist`/`tab`/`tabpanel` ARIA pattern. Arrow key navigation within the tab list, Tab to move focus into the panel. This is the keyboard interaction model to copy.
42
+ - **[shadcn/ui Tabs](https://ui.shadcn.com/docs/components/tabs)** — clean Radix implementation showing horizontal and vertical orientations.
43
+ - **[Linear's sidebar tabs](https://linear.app)** — vertical tabs in a sidebar context; icon+label on wider widths, icon-only on narrower widths with tooltip.
44
+
45
+ ### Minimum quality bar
46
+
47
+ - [ ] `role="tablist"` on container, `role="tab"` on each trigger, `role="tabpanel"` on each panel
48
+ - [ ] `aria-selected="true"` on the active tab, `aria-controls` pointing to its panel
49
+ - [ ] Arrow keys (Left/Right for horizontal, Up/Down for vertical) navigate between tabs
50
+ - [ ] Tab key moves focus into the active panel, not to the next tab
51
+ - [ ] Active tab is visually distinct from inactive — not just a color change (underline or elevated background)
52
+ - [ ] If tabs can have counts or badges, they don't overflow the tab trigger width
53
+
54
+ ### Common mistakes
55
+
56
+ - Building tabs with buttons and state — without the ARIA roles, screen readers can't identify the pattern
57
+ - Tab key navigating between tabs — breaks the WAI-ARIA tabs keyboard spec
58
+ - Tabs that look like navigation links but don't change the URL — confuse back button behavior
59
+
60
+ ---
61
+
62
+ ## Sidebar Navigation
63
+
64
+ A persistent vertical list of destinations, usually for primary navigation in dense applications. The sidebar is either always visible (persistent) or toggled (collapsible).
65
+
66
+ ### Reference implementations
67
+
68
+ - **[Linear's sidebar](https://linear.app)** — collapsible sections with disclosure triangles, drag-to-reorder items, keyboard-accessible, active item highlighted with subtle background. The state of each section persists across sessions.
69
+ - **[shadcn/ui Sidebar](https://ui.shadcn.com/docs/components/sidebar)** — comprehensive implementation with collapsible, icon-only mode, groups, and responsive mobile sheet behavior.
70
+ - **[Radix UI Navigation Menu](https://www.radix-ui.com/primitives/docs/components/navigation-menu)** — for nested navigation with flyout submenus.
71
+
72
+ ### Minimum quality bar
73
+
74
+ - [ ] `<nav>` element with `aria-label` distinct from any other nav
75
+ - [ ] Active item has `aria-current="page"` and a visual highlight (not just color)
76
+ - [ ] Collapsible sections use `<button>` with `aria-expanded`; the trigger is not the section heading itself
77
+ - [ ] Keyboard: arrow keys navigate the tree; Enter expands/collapses; Escape collapses
78
+ - [ ] Mobile: either always visible (if space allows) or a toggleable sheet/drawer — not a hamburger that hides destinations
79
+
80
+ ### Common mistakes
81
+
82
+ - Using `<ul>` and `<li>` without navigation semantics — consider `role="navigation"` and `aria-label`
83
+ - Active state using only color — inaccessible; add icon, weight, or background differentiation
84
+ - Sidebar that hides off-screen on mobile but is still Tab-focusable — focus trap for keyboard users
85
+
86
+ ---
87
+
88
+ ## Breadcrumb
89
+
90
+ Shows the user's location in a hierarchy and lets them jump to any ancestor level. Useful in deeply nested navigation trees; not needed for flat applications.
91
+
92
+ ### Reference implementations
93
+
94
+ - **[Radix UI Breadcrumbs](https://www.radix-ui.com/themes/docs/components/breadcrumbs)** — correct `<nav aria-label="Breadcrumb">` wrapper with `<ol>` and `aria-current="page"` on the last item.
95
+ - **[GitHub Primer Breadcrumb](https://primer.style/react/storybook/?path=/story/components-breadcrumbs--default)** — good handling of overflow: ellipsis in the middle, not at the start or end.
96
+
97
+ ### Minimum quality bar
98
+
99
+ - [ ] `<nav aria-label="Breadcrumb">` wrapper around an `<ol>`
100
+ - [ ] Last item has `aria-current="page"` and is not a link (it's the current page)
101
+ - [ ] Separator (/) between items is decorative — `aria-hidden="true"` or CSS-generated
102
+ - [ ] On mobile/constrained width: truncate middle items, always show root and current
103
+ - [ ] Schema.org `BreadcrumbList` structured data for SEO when breadcrumbs appear in public pages
104
+
105
+ ### Common mistakes
106
+
107
+ - Making the current page item a link — it should not be; it is the current location
108
+ - Separators that are part of the link's tab stop — separators are decorative
109
+
110
+ ---
111
+
112
+ ## Dropdown Menu
113
+
114
+ A contextual list of actions, exposed from a trigger element. Not a select (select chooses a value); a menu triggers actions.
115
+
116
+ ### Reference implementations
117
+
118
+ - **[Radix UI Dropdown Menu](https://www.radix-ui.com/primitives/docs/components/dropdown-menu)** — the complete reference: `menu`, `menuitem`, `menuitemcheckbox`, `menuitemradio` roles, keyboard navigation (arrow keys, Home/End, typeahead), sub-menus, separators.
119
+ - **[shadcn/ui Dropdown Menu](https://ui.shadcn.com/docs/components/dropdown-menu)** — clean implementation with icons, keyboard shortcuts displayed inline, destructive item styling.
120
+ - **[Linear's context menus](https://linear.app)** — observe: keyboard shortcuts shown in the menu (⌘D), dividers grouping related actions, destructive actions at the bottom, subtle hover highlight.
121
+
122
+ ### Minimum quality bar
123
+
124
+ - [ ] `role="menu"` on the list, `role="menuitem"` (or `menuitemcheckbox`/`menuitemradio`) on items
125
+ - [ ] Arrow keys navigate; Enter/Space activates; Escape closes and returns focus to trigger
126
+ - [ ] Typeahead: pressing a letter jumps to first item starting with that letter
127
+ - [ ] Nested submenus open on arrow-right; close on arrow-left or Escape
128
+ - [ ] Destructive items visually distinct (red label); positioned last in the group
129
+ - [ ] Menu closes when user clicks outside or navigates away; focus returns to trigger
130
+
131
+ ### Common mistakes
132
+
133
+ - Using a dropdown menu for a select — `role="menu"` does not communicate value selection to screen readers
134
+ - Not returning focus to the trigger when the menu closes
135
+ - Sub-menus that open on hover (not arrow key) — inaccessible keyboard pattern
136
+
137
+ ---
138
+
139
+ ## Pagination
140
+
141
+ Controls for navigating through paged data. Users need to know their current position, total pages (if known), and where to go next.
142
+
143
+ ### Reference implementations
144
+
145
+ - **[shadcn/ui Pagination](https://ui.shadcn.com/docs/components/pagination)** — previous/next arrows with page number range in between; ellipsis for large ranges.
146
+ - **[GitHub Primer Pagination](https://primer.style/components/pagination)** — handles `aria-label` per page link ("Page 2"), `aria-current="page"` on the active page, previous/next with icon + text.
147
+
148
+ ### Minimum quality bar
149
+
150
+ - [ ] `<nav aria-label="Pagination">` wrapping the controls
151
+ - [ ] Each page link has a unique, descriptive `aria-label` ("Page 3")
152
+ - [ ] Current page has `aria-current="page"` and is not a link
153
+ - [ ] Previous/Next buttons are disabled (not hidden) on the first/last page; `aria-disabled="true"` and `disabled`
154
+ - [ ] Ellipsis items are not interactive and are `aria-hidden="true"`
155
+ - [ ] Keyboard: Tab reaches each page link; Enter activates
156
+
157
+ ### Common mistakes
158
+
159
+ - Hiding previous on page 1 and next on last page — users lose spatial context about the range
160
+ - Ellipsis items that are also links — they should not be clickable
161
+
162
+ ---
163
+
164
+ ## Command Palette
165
+
166
+ A keyboard-first search interface for navigating and acting across the entire application. Found in Linear, VSCode, GitHub, Vercel. The power-user's primary navigation.
167
+
168
+ ### Reference implementations
169
+
170
+ - **[cmdk](https://cmdk.paco.me/)** — the canonical open-source command palette component; accessible, keyboard-driven, fuzzy search, used by shadcn/ui and Linear.
171
+ - **[Linear's command palette](https://linear.app)** — press `⌘K`; observe: fuzzy search, grouping, keyboard shortcuts shown, recent items at top, no mouse required after open.
172
+ - **[shadcn/ui Command](https://ui.shadcn.com/docs/components/command)** — cmdk with Tailwind styling; includes the modal wrapper pattern.
173
+
174
+ ### Minimum quality bar
175
+
176
+ - [ ] Opens with `⌘K` (Mac) / `Ctrl+K` (Windows/Linux); closes with Escape
177
+ - [ ] Focus is trapped inside while open; returns to previous element on close
178
+ - [ ] Search input is focused immediately on open
179
+ - [ ] Keyboard: arrow keys navigate items; Enter activates; Tab should also navigate
180
+ - [ ] Items are grouped (e.g. "Navigation", "Actions", "Recent")
181
+ - [ ] Empty state is shown when no matches (not a blank list)
182
+ - [ ] `role="combobox"` on the input, `role="listbox"` on the list, `role="option"` on items
183
+
184
+ ### Common mistakes
185
+
186
+ - Requiring mouse to open — defeats the purpose of a keyboard-first tool
187
+ - No empty state — users don't know if the search is broken or there are no results
188
+ - Slow filtering — command palettes must filter on every keystroke instantly (<16ms)
@@ -0,0 +1,188 @@
1
+ # Surface — UI References
2
+
3
+ Surface components are containers and overlays: they frame content, present it in context, and layer it above other content. The quality of a surface shows in its edge cases — what happens when content overflows, when it's positioned near a viewport edge, or when a screen reader announces it.
4
+
5
+ ---
6
+
7
+ ## Card
8
+
9
+ A bounded content container that groups related information. Cards are surfaces, not actions: they can be clickable (linking to detail views) but clicking a card is navigation, not a form submission.
10
+
11
+ ### Reference implementations
12
+
13
+ - **[shadcn/ui Card](https://ui.shadcn.com/docs/components/card)** — `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter` composition pattern; clear separation of structural slots.
14
+ - **[Radix UI Card](https://www.radix-ui.com/themes/docs/components/card)** — minimal themed card with consistent shadow and radius; good baseline for a design system.
15
+ - **[Linear's cards](https://linear.app)** — observe in issues and project views: no excessive shadow, border defines the edge, hover state is a background tint (not elevation change), active selection uses a strong left border.
16
+ - **[Vercel/Geist Card](https://vercel.com/geist/components)** — flat cards with border; the standard for enterprise/dashboard contexts.
17
+
18
+ ### Minimum quality bar
19
+
20
+ - [ ] Consistent internal padding (match the project's grid unit)
21
+ - [ ] Container border-radius matches the project's `container` radius value — not the `control` radius
22
+ - [ ] If the whole card is clickable: `<a>` wrapping the card (not an `onClick` on a `<div>`)
23
+ - [ ] If part of the card is clickable (e.g. title link + action button): use `::after` pseudo-element on the title link to expand its hit area to the card; action button has its own event without conflict
24
+ - [ ] Hover state is visible; active/pressed state is visible
25
+ - [ ] Card body does not use `overflow: hidden` aggressively — truncation should be controlled and indicated
26
+
27
+ ### Common mistakes
28
+
29
+ - Wrapping an entire card in `<a>` when it also contains buttons — creates nested interactive elements and confuses screen readers
30
+ - Elevation (box-shadow) as the primary border — elevation should supplement, not replace, a visible edge
31
+ - Fixed height cards that hide overflow without indication — use truncation with ellipsis and tooltip, not silent clipping
32
+
33
+ ---
34
+
35
+ ## Popover
36
+
37
+ A floating overlay anchored to a trigger element. Used for secondary actions, rich tooltips, or inline editing. Differs from a tooltip: popovers can contain interactive elements.
38
+
39
+ ### Reference implementations
40
+
41
+ - **[Radix UI Popover](https://www.radix-ui.com/primitives/docs/components/popover)** — the reference: `role="dialog"` when interactive, focus moves into the popover on open, Escape closes and returns focus. `side`, `align`, and `avoidCollisions` handle positioning near viewport edges.
42
+ - **[shadcn/ui Popover](https://ui.shadcn.com/docs/components/popover)** — Radix Popover with Tailwind; shows the trigger + content pattern cleanly.
43
+ - **[Floating UI](https://floating-ui.com/)** — the positioning library underlying Radix, Headless UI, and others; consult for edge cases in custom positioning logic.
44
+
45
+ ### Minimum quality bar
46
+
47
+ - [ ] `role="dialog"` with `aria-label` or `aria-labelledby` when the popover contains interactive content
48
+ - [ ] Focus moves into the popover when it opens (for interactive popovers)
49
+ - [ ] Escape closes the popover; click outside closes; focus returns to trigger
50
+ - [ ] Stays within viewport: flips side and/or shifts along axis when near an edge
51
+ - [ ] Arrow indicator (optional but helpful) points to the anchor and repositions when the popover flips
52
+ - [ ] Does not scroll the page body when scrolling inside the popover
53
+
54
+ ### Common mistakes
55
+
56
+ - Non-interactive popovers that receive focus — only interactive popovers should trap/move focus
57
+ - Popover that overflows the viewport on small screens — always test positioning at mobile widths
58
+ - Opening a popover on hover without a click fallback — hover-only is inaccessible
59
+
60
+ ---
61
+
62
+ ## Tooltip
63
+
64
+ A small informational overlay that appears on hover (and focus). Tooltips explain UI elements; they do not contain interactive elements. If you need interactive content in the overlay, use a Popover.
65
+
66
+ ### Reference implementations
67
+
68
+ - **[Radix UI Tooltip](https://www.radix-ui.com/primitives/docs/components/tooltip)** — `role="tooltip"` on the content, `aria-describedby` linking the trigger to the tooltip. Delay before showing (300ms default), immediate hide on mouse leave.
69
+ - **[shadcn/ui Tooltip](https://ui.shadcn.com/docs/components/tooltip)** — clean implementation; the `TooltipProvider` wrapping pattern for shared delay configuration.
70
+ - **[Floating UI Tooltip tutorial](https://floating-ui.com/docs/tooltip)** — explains hover + focus event handling without ARIA mistakes.
71
+
72
+ ### Minimum quality bar
73
+
74
+ - [ ] `role="tooltip"` on the content element
75
+ - [ ] Trigger has `aria-describedby` pointing to the tooltip id
76
+ - [ ] Shows on hover AND on keyboard focus (not hover only)
77
+ - [ ] Delay before showing (200–300ms) prevents tooltip flicker on cursor pass-through
78
+ - [ ] Tooltip is dismissible via Escape key while visible
79
+ - [ ] Does not obscure the element being described
80
+ - [ ] Text content only — if you need a button inside, it's a Popover
81
+ - [ ] Respects `prefers-reduced-motion` for entry animation
82
+
83
+ ### Common mistakes
84
+
85
+ - Tooltip on a disabled element — disabled elements don't receive focus events; wrap the disabled element in a `<span>` for the tooltip
86
+ - Tooltip that duplicates the visible label exactly — adds no value; tooltip text should supplement, not repeat
87
+ - Interactive content (links, buttons) inside a tooltip — use Popover instead
88
+
89
+ ---
90
+
91
+ ## Sheet / Drawer
92
+
93
+ A panel that slides in from an edge of the screen (most commonly the right). Used for secondary task panels, filter drawers, detail views, or mobile navigation.
94
+
95
+ ### Reference implementations
96
+
97
+ - **[shadcn/ui Sheet](https://ui.shadcn.com/docs/components/sheet)** — four opening directions (top, right, bottom, left); `role="dialog"`, focus trap, Escape to close; uses the Radix UI Dialog primitive underneath.
98
+ - **[Radix UI Dialog as Sheet](https://www.radix-ui.com/primitives/docs/components/dialog)** — sheets are typically implemented on top of a dialog primitive with CSS positioning.
99
+ - **[Linear's right panel](https://linear.app)** — observe the issue detail panel: slides in from the right, does not cover the main content at wider viewports (side-by-side layout), full-screen on mobile.
100
+
101
+ ### Minimum quality bar
102
+
103
+ - [ ] `role="dialog"`, `aria-modal="true"`, `aria-label` or `aria-labelledby`
104
+ - [ ] Focus trap: Tab/Shift+Tab cycle inside the sheet while open
105
+ - [ ] Opens with slide animation; closes with slide animation; `prefers-reduced-motion` respects instant open/close
106
+ - [ ] Escape closes; clicking the scrim closes; close button always visible
107
+ - [ ] On mobile: always full-screen or nearly full-screen — partial drawers cause content-below-fold confusion
108
+ - [ ] Handles soft keyboard on mobile (input fields inside the sheet must be visible when keyboard opens)
109
+
110
+ ### Common mistakes
111
+
112
+ - Sheet that cannot be closed without completing a form — always allow escape/scrim close
113
+ - Sheet that scrolls the background page — lock body scroll while sheet is open
114
+ - Nested sheets — avoid; create a single sheet that can change its contents instead
115
+
116
+ ---
117
+
118
+ ## Avatar
119
+
120
+ Represents a user or entity with an image, initials, or icon. Appears in lists, comments, headers, and presence indicators.
121
+
122
+ ### Reference implementations
123
+
124
+ - **[Radix UI Avatar](https://www.radix-ui.com/primitives/docs/components/avatar)** — image with `AvatarFallback` that shows while image loads or on error. The fallback timing (delay before fallback renders) avoids flash-of-initials before the image loads.
125
+ - **[shadcn/ui Avatar](https://ui.shadcn.com/docs/components/avatar)** — clean implementation; the image + fallback pattern with consistent sizing.
126
+
127
+ ### Minimum quality bar
128
+
129
+ - [ ] Image has `alt` text describing who it represents (not `alt=""` — that's for decorative images)
130
+ - [ ] Fallback (initials or generic icon) when image fails to load or is not provided
131
+ - [ ] Fallback renders deterministically — same initials/color every time for the same user
132
+ - [ ] Consistent sizes across the product — define a size scale (sm/md/lg) and stick to it
133
+ - [ ] Avatar groups (stacked avatars): `z-index` and margin-left negative offset done with CSS, not absolute positioning
134
+
135
+ ### Common mistakes
136
+
137
+ - `alt=""` on user avatar images — these are meaningful, not decorative; describe who the image shows
138
+ - Avatar that shows a broken image icon instead of fallback — always handle image load failure
139
+ - Fallback background color that is too light against a white background — ensure sufficient contrast
140
+
141
+ ---
142
+
143
+ ## Separator / Divider
144
+
145
+ A visual line that separates groups of content. Structural, not decorative — it communicates that what's above and below belong to different groups.
146
+
147
+ ### Reference implementations
148
+
149
+ - **[Radix UI Separator](https://www.radix-ui.com/primitives/docs/components/separator)** — `role="separator"` (structural) or `role="none"` (decorative), horizontal and vertical orientation.
150
+ - **[shadcn/ui Separator](https://ui.shadcn.com/docs/components/separator)** — thin horizontal/vertical rule.
151
+
152
+ ### Minimum quality bar
153
+
154
+ - [ ] `role="separator"` when the line communicates structure (between sections); `role="none"` or `aria-hidden="true"` when purely decorative
155
+ - [ ] Color passes 3:1 contrast against its background
156
+ - [ ] Does not carry margin by default — let the container control spacing
157
+ - [ ] Horizontal separators extend to the full width of their container unless explicitly inset
158
+
159
+ ### Common mistakes
160
+
161
+ - Using `<hr>` inside inline contexts — `<hr>` has block display; use `role="separator"` on a `<span>` for inline separators
162
+ - Separator with too much vertical margin — creates too much visual space between related groups
163
+
164
+ ---
165
+
166
+ ## Badge
167
+
168
+ A small label applied to an element to communicate status, count, or category. Appears inline next to text or as an overlay on an icon.
169
+
170
+ ### Reference implementations
171
+
172
+ - **[shadcn/ui Badge](https://ui.shadcn.com/docs/components/badge)** — variant system (default, secondary, destructive, outline); small, not button-like.
173
+ - **[Radix UI Badge](https://www.radix-ui.com/themes/docs/components/badge)** — color-coded badges with good contrast defaults across themes.
174
+ - **[Linear's labels](https://linear.app)** — observe issue labels: colored dot + text, keyboard accessible in filter panels, consistent small size.
175
+ - **[GitHub Primer Label](https://primer.style/components/label/react/alpha)** — handles "filled" and "outline" variants with color theming.
176
+
177
+ ### Minimum quality bar
178
+
179
+ - [ ] Not a button — badges are not interactive; if clicking a badge does something, it should be a `<button>` or `<a>` visually styled as a badge
180
+ - [ ] Text must pass 4.5:1 contrast against its background color
181
+ - [ ] Numeric badges (notification counts): `aria-label="N notifications"` on the parent container; the badge itself is `aria-hidden`
182
+ - [ ] Never convey information through color alone — include text or icon alongside color coding
183
+ - [ ] Consistent height and padding across all badge uses in the product
184
+
185
+ ### Common mistakes
186
+
187
+ - Badge that is a `<div>` with `onClick` — should be `<button>` for interactivity or `<span>` for decoration
188
+ - Too many badge variants — three variants (default, success, danger) cover most cases; more adds cognitive load