| name | design-components |
| description | Build a reusable UI component library for a full-stack Rails 8.1 app — choose the component architecture (ViewComponent, Phlex, or ERB partials), adopt a UI kit (daisyUI, Flowbite, Tailwind UI, or hand-rolled Tailwind), and preview/document components in isolation with Lookbook. Menu-driven with a Recommended default per menu; detects the view layer the app already chose (honors installed view_component/phlex-rails) and the installed UI kit first, builds components from the tokens design-foundations established, and verifies they render in isolation and in a page. Apply when creating buttons/cards/badges/component primitives, organizing a design system, integrating a UI kit, or setting up component previews. Web apps only. |
| metadata | {"owner":"rails-design","status":"stable"} |
| user-invocable | true |
| argument-hint | [component] |
design-components
Purpose
Owns the reusable UI component layer of a Hotwire app — the design-system building
blocks (buttons, cards, badges, alerts, avatars, the variants/sizes/slots that make
them reusable), the architecture that holds them (ViewComponent, Phlex, or ERB
partials), the UI kit they're built from (daisyUI / Flowbite / Tailwind UI /
hand-rolled), and how they're previewed and documented (Lookbook). It consumes the
tokens from ../design-foundations/ and bakes accessibility from
../design-accessibility/ into each component. The base view-layer pick is owned by
../rails-hotwire/; this skill applies the design-system lens to it and builds the
library on top.
When to Apply
Use this skill when the task is:
- Building reusable component primitives (button, card, badge, alert, avatar, modal shell)
- Defining a component's variants / sizes / states / slots for reuse
- Choosing how to structure the component library (ViewComponent vs Phlex vs partials) for a design system
- Adopting or integrating a UI kit (daisyUI/Flowbite/Tailwind UI) or going hand-rolled
- Setting up component previews / documentation (Lookbook)
Do not use this skill when the task is:
- Defining the tokens (colors/spacing/type) the components use → read
../design-foundations/SKILL.md
- Page layout / app shell / navigation assembled from components → read
../design-layout-navigation/SKILL.md
- Interactive behavior (modal open/close, dropdown toggling, toasts) → read
../design-interactions/SKILL.md
- Form fields and validation UX → read
../design-forms/SKILL.md
- The base view-layer choice / Turbo & Stimulus wiring → read
../rails-hotwire/SKILL.md (it owns the plumbing; this skill builds the library within it)
- A component's full a11y audit → read
../design-accessibility/SKILL.md
- An API-only app — no UI components
Detect Before You Generate
grep -nE "api_only" config/application.rb
bundle list 2>/dev/null | grep -E "view_component|phlex|lookbook"
ls app/components 2>/dev/null && echo "→ component dir exists"
grep -E "daisyui|flowbite" Gemfile.lock package.json 2>/dev/null
find app/views -name '_*.html.erb' -print -quit 2>/dev/null
ls test/components spec/components 2>/dev/null
- If a view layer is already installed, use it silently.
view_component in the
bundle + app/components/ → ViewComponent; phlex-rails → Phlex; only partials → ERB.
Don't introduce a second architecture — match what's there.
- Detect the UI kit before adding one; build on the installed kit's classes.
- If Lookbook is installed, generate previews for new components by default.
Menu
Three menus via AskUserQuestion; the design-system default marked Recommended.
Ask unless detection already settles the pick.
Component architecture (design-system lens; ../rails-hotwire/ owns the base pick)
| Option | One-line trade-off | Deep dive |
|---|
| ViewComponent (Recommended) | Ruby class + template, unit-testable, slots, Lookbook-native. The proven choice for a real design system. | viewcomponent.md |
| Phlex | Components as pure Ruby (no template files); fast, composable, refactor-friendly. Bigger shift from ERB. | phlex.md |
| ERB partials + helpers | Rails default, zero deps; fine for a handful of shared snippets. Sprawls without encapsulation/tests at scale. | erb-partials.md |
UI kit
| Option | One-line trade-off | Deep dive |
|---|
| daisyUI (Recommended) | Semantic Tailwind component classes (btn, card) + themes; least markup, themeable, no JS bloat. | ui-kit-daisyui.md |
| Flowbite | 600+ Tailwind components with interactive JS; lots ready to copy, heavier CSS + its own JS. | ui-kit-flowbite.md |
| Tailwind UI (paid) | Official hand-crafted templates; top quality, license cost, copy-paste (not a dependency). | ui-kit-flowbite.md (covers Tailwind UI too) |
| Hand-rolled utilities | Build from raw Tailwind utilities + tokens; total control, most effort, smallest surface. | component-anatomy.md |
Component previews / docs
| Option | One-line trade-off | Deep dive |
|---|
| Lookbook (Recommended) | Isolated previews + states for ViewComponent/Phlex; living design-system docs, the visual-QA surface. | lookbook-previews.md |
| None | Skip until the library is big enough to warrant a gallery; preview in real pages only. | lookbook-previews.md |
Decision Flow
- Architecture: if the app already picked one (detect), use it. For a new design
system, ViewComponent — encapsulation, slots, unit tests, and first-class Lookbook
previews are exactly what a component library needs. Choose Phlex if the team wants
Ruby-all-the-way and maximum composability. Stay on ERB partials for a small set of
shared snippets where a framework is overkill. (The base view-layer trade-off lives in
../rails-hotwire/.)
- UI kit: daisyUI for the least markup and built-in theming that rides on your
tokens; Flowbite when you want a big catalog of prebuilt interactive components;
Tailwind UI when you'll buy and adapt premium templates; hand-rolled when brand
fidelity beats speed. You can use a kit through components — wrap kit classes in a
ViewComponent so call sites stay semantic.
- Variants over forks. Express differences as
variant:/size: parameters, not
copy-pasted components — see component-anatomy.md.
- Previews: add Lookbook as soon as you have more than a few components — it's
living documentation and the surface
../design-visual-qa/ reviews against.
- Bake in a11y at the source. Each primitive ships correct semantics, names, and
focus styles per
../design-accessibility/ so every call site inherits them.
Problem → Reference
Verify
A component is "done" when it renders in isolation and in a real page, with its
variants and a11y intact:
bin/rails test test/components 2>/dev/null || bundle exec rspec spec/components
bin/rails server -d && sleep 3
curl -fsS localhost:3000/lookbook -o /dev/null -w "lookbook=%{http_code}\n" 2>/dev/null
curl -fsS localhost:3000/ -o /tmp/p.html && grep -qE "btn|card|badge" /tmp/p.html && echo "✓ components render in page"
kill "$(cat tmp/pids/server.pid)"
Eyeball each variant/size/state in Lookbook, confirm tokens (../design-foundations/)
flow through, then route to ../design-accessibility/ for the a11y audit and
../design-visual-qa/ to lock the rendering with tests.