One design system, four products, zero copies
Woohl components install through the shadcn CLI and land in your repo as source you own. Dependencies resolve themselves. Nothing to publish, nothing to version, nothing to keep in sync by hand.
bunx --bun shadcn@latest add @woohl/buttonTokens & brand
5 itemsThe values everything else resolves against.
Tokens & themes
The whole token layer: colour, type, spacing, radius, shadow, motion, z-index and breakpoints, plus the four product themes. Every other item assumes these are present.
Constants
Icon sizes, image ratios, currency and the other numbers the components agree on.
Token metadata
Human-readable descriptions of every token, for docs and swatch tables.
Brand marks
WoohlLogo, WoohlBird, WoohlWordmark, WoohlBullet and WoohlAppIcon, drawn from the canonical path data. Never rebuild the logo from text.
Imagery
WoohlImage with the house aspect ratios, placeholder treatment and scrim helpers for text over photography.
Primitives
7 itemsLow-level pieces the components are built from.
cn()
The class merger, configured for Woohl's custom utilities.
cva helpers
Variant authoring plus the shared focus-ring, disabled and touch-target fragments.
Accessibility hooks
Focus trap, escape key, click-outside, scroll lock, arrow-key navigation and contrast maths.
Structural glyphs
The handful of marks a control draws as part of itself — tick, cross, caret, alert. Not an icon set: content icons come from your app through an `icon` prop.
IconSlot
The seam where your app's icon enters a Woohl component. Owns optical size so a 15px icon stays 15px whichever library drew it.
Separator
A hairline, with an optional word in the middle.
Skeleton
A grey block standing in for content that has not arrived.
Components
10 itemsStandalone, reusable controls.
Button
Six levels of emphasis, four sizes, loading and icon-only states.
Input & Textarea
Text fields with the wrapper that lets an icon or prefix sit inside the box.
Badge & Chip
Status and category labels, plus the removable chip.
Avatar
Initials on a brand tint until the photograph decodes, with the Assured tick and stacked groups.
Switch
For settings that take effect immediately — not for form values you are about to submit.
Checkbox
Including a real indeterminate state that announces as mixed.
RadioGroup
A group that owns the value and the roving tabindex.
Tooltip
Supplementary hints on hover and focus. Never an accessible name.
Field & Label
Label, hint, error and the aria wiring between them.
Card
Five surfaces, four padding steps, and the header/footer parts.
Composites
10 itemsOverlays and structures made of several parts.
Dialog
Modal with focus trap, scroll lock and the rest of the page hidden from screen readers. Prop-driven and composition APIs both.
Drawer & Sheet
A dialog that arrives from an edge, for a place you can stay rather than a question you must answer.
Dropdown menu
Typeahead, arrow keys, submenus, checkbox and radio items.
Popover
An anchored panel that can hold anything, including a form.
Select
A styleable listbox, plus NativeSelect for long lists on touch.
Tabs
Underline and segmented variants, array-driven or composed.
Table
Real table semantics, plus a sortable DataTable.
Pagination
A windowed page list and the range summary beside it.
Toast & Alert
The transient queue and the inline banner, sharing one tone scale.
Navigation
Breadcrumb, nav list, navbar, side nav and skip link.
Blocks
12 itemsMarketplace compositions, opinionated on purpose.
Price
Rupee formatting, compare-at strikethrough and the saving line.
Rating
Stars with a count, and the five-bar breakdown.
Wishlist button
The heart toggle, with outline/fill as a second signal beside colour.
Quantity selector
A stepper that respects stock limits.
Product card
The marketplace tile: image, maker, price, rating, wishlist.
Product grid
The responsive grid the cards sit in, with a matching skeleton.
Cart item & summary
A bag line with quantity and remove, plus the totals block.
Seller card
The maker: avatar, place, year, Assured tick, and their quote.
Order status & timeline
Status as badge or block, and the vertical progress timeline.
Address card
A labelled delivery address with default and edit affordances.
Empty & error states
Say what happened and offer the way out.
Search
A combobox field with a suggestion listbox and full keyboard support.