# Dowel — full reference Generated from @dowel-ui/react@0.8.0. Canonical source: https://dowel-eight.vercel.app --- # Dowel — conventions Rules for writing code in this project. Dowel is **source-first**: its components are files in this repository, not a dependency you can reason about from its README. They are yours to edit, and edits are preserved across updates. ## The rule that matters most **Do not hand-write a component that Dowel already has.** Check the catalogue in `components.md` first. Writing a second Button — with different focus rings, different disabled semantics, different tokens — is the single most common and most damaging thing to do here. ## Adding a component ```bash npx @dowel-ui/cli add ``` This writes the source into the project and installs whatever it depends on. `add` is safe to re-run: an untouched file is left alone, an edited one is never overwritten without `--overwrite`. Do not `npm install` a component. Do not copy source out of the documentation by hand — the CLI resolves the dependency graph and rewrites imports to this project's path alias, and doing it manually gets both wrong. ## Importing ```tsx import { Button, Card, CardContent } from "@dowel-ui/react"; ``` ## Styling - Use semantic tokens (`bg-background`, `text-foreground`, `border-border`, `ring-ring`, `bg-primary`, `text-muted-foreground`). Never raw hex, and never Tailwind's own palette (`bg-slate-900`, `text-gray-500`) — those do not follow the theme and break every preset and dark mode. - Spacing, radius and type come from the scale. `rounded-md` and `rounded-lg` re-proportion with `--radius-scale`; an arbitrary `rounded-[7px]` does not. - Durations derive from `--motion-scale`. Do not hardcode transition timings. - Compose class names with `cn()` from the project's utils, so consumer overrides win over defaults. ## Accessibility Targeted at WCAG 2.2 AA, verified with axe per component. Where Dowel differs from what you have seen in other libraries: - A loading `Button` uses `aria-disabled` + `aria-busy` and guards its own click handler. Never add `disabled` to it — disabling a control mid-action strands keyboard focus. - `Alert` is not a live region by default. One that exists on first paint announces for no reason. Opt in with `live="polite"` or `live="assertive"` only when the alert appears in response to something. - `Separator`, `Skeleton` and `Spinner` are decorative and stay out of the accessibility tree unless given a label. Do not add `role` or `aria-label` to them by reflex. - `PopoverContent` carries `role="dialog"` and warns in development without an accessible name. Always give it `aria-label` or `aria-labelledby`. - Never use colour as the only signal. The `monochrome` preset exists as a standing check on exactly this — if a state is unreadable under it, the component is wrong. ## Before you build a page Check `components.md` for a **block** that already covers it. A block is a whole section — a login form, a settings page, a chat surface — and installing one brings every component it is assembled from. Building a dashboard out of individual primitives when `add dashboard` exists is wasted work. ## Reference - Documentation: https://dowel-eight.vercel.app - Full text for models: https://dowel-eight.vercel.app/llms-full.txt --- # Dowel — catalogue 184 components and 51 blocks, generated from `@dowel-ui/react@0.8.0`. This is the complete list — anything not here does not exist. ## Foundation - **button** — Triggers an action or event, with variants for every level of emphasis. - **direction** — Tells the component primitives which way the writing runs, so menus and sliders mirror with the rest of the page. ## Forms - **animated-checklist** — A task list whose boxes fill with a bounce and whose done tasks fade and strike through, with an add row. _(beta)_ - **app-stack** — A pile of app icons that fans out on hover and opens into a multi-select picker whose icons fly to their tiles. _(beta)_ - **assignee-picker** — A pill of overlapping faces that opens a multi-select list of people; new faces fly into the stack. _(beta)_ - **calendar** — A date grid for selecting a day, several days or a range. - **checkbox** — A control for an on/off choice, with support for an indeterminate state. - **combobox** — A searchable single-select built on the ARIA combobox pattern. - **confirm-typed** — Type the name to confirm — and be told, not ignored, when it does not match. - **copy-button** — Copies a value to the clipboard and morphs its icon and label into a confirmation that reverts on its own. _(beta)_ - **cron-editor** — A schedule as a cron expression, with a plain-language reading and the next runs. - **date-picker** — A button that opens a calendar to pick a date or a date range. - **dial** — A rotary dial input — a knob inside a filling arc with detent ticks — turned by drag, wheel or keys. _(beta)_ - **dot-morph-button** — A pill button led by a dot that stretches into a bar on hover and keyboard focus. _(beta)_ - **drag-stepper** — A pill number stepper: tap − or + to step, or hold either one to stretch into a sweep and drag to scrub. _(beta)_ - **effect-button** — A Button with a hover and focus micro-interaction — slide-arrow, pulse, rotate, shake, glare, text reveal, expanding ring or clip corners. _(beta)_ - **expanding-search** — A search button that opens into a field, clears, and collapses back with Escape — ready for a combobox. _(beta)_ - **exposure-slider** — A camera-style exposure dial: a draggable ruler of notches under a fixed centre mark, with a value ring. _(beta)_ - **file-upload** — A dropzone over a real file input, plus the upload queue nobody ships. - **form** — Accessible field wiring that works with any form library, or none. - **image-selector** — A photo grid with a Select mode: tick photos, see the count, share or delete them, and reset. _(beta)_ - **inline-confirm** — A destructive button that asks in place — it widens into Keep / Delete, then offers a timed Undo. _(beta)_ - **input** — A single-line text field with size variants and native validation styling. - **label** — An accessible caption that associates text with a form control. - **liquid-toggle** — A switch whose knob squashes like a droplet as it travels, and can be dragged across. _(beta)_ - **magnetic-button** — A button that drifts toward the pointer — optionally with its label leaning further — and springs back when it leaves. _(beta)_ - **magnetic-select** — A honeycomb of round chips: choosing one grows it and magnetically shoves the rest apart, tilted, with a springy settle. _(beta)_ - **morph-button** — A button whose icon and label morph to an active state — toggles, transient confirmations and hover affordances. _(beta)_ - **notify-button** — A “notify me” toggle: the bell rings and the label grows elastically into the confirmation. _(beta)_ - **otp-input** — A one-time-code field drawn as a row of animated slots — paste, SMS autofill, masking and grouping included. _(beta)_ - **radio-group** — A set of mutually exclusive options. - **range-dial** — A 24-hour circular two-thumb range — drag or key the start and end round a ticked clock face, with the duration in the middle. _(beta)_ - **reorder-list** — A short list of people or things you put in order by dragging liquid pills, or with Space and the arrow keys. _(beta)_ - **scrubber** — A design-tool number field: drag across a labelled bar to scrub a value, step it from the keyboard, or type it. _(beta)_ - **secret-field** — An API key in its three states: shown once, hidden but revealable, and gone. - **select** — Picks one value from a short list of options. - **selection-list** — A multi-select list of people with a liquid tick and an action that springs out from under it once someone is picked. _(beta)_ - **shortcut-recorder** — Press the keys you want: records a chord, platform-aware, and says when it clashes. - **slide-to-confirm** — A track whose grip you slide to the end to confirm — bencho's wash-and-morph pill or SmoothUI's power-off slide — with a press-and-hold path. _(beta)_ - **slider** — Selects a value, or a range, from a continuous span. - **slosh-slider** — A slider whose fill behaves like liquid: the knob jumps to the value while the fill springs after it, leaning as it moves. _(beta)_ - **social-selector** — Pick a social platform from a row of icons — a pill slides behind the choice and the caption links to the profile. _(beta)_ - **switch** — An immediate on/off toggle for settings that apply straight away. - **tags-input** — A list of short values, where invalid entries stay visible instead of vanishing. - **textarea** — A multi-line text field, with optional auto-resize and a character count that knows when to stay quiet. - **time-range-picker** — A time range whose value is an expression, so it stays relative across a reload. ## Overlays - **account-menu** — An avatar that opens an account panel of collapsible sections — edit the profile, check recent orders. _(beta)_ - **context-menu** — A right-click menu that pops from the pointer with a spring and staggers its items in — same parts as Dropdown Menu. _(beta)_ - **dialog** — A modal window that interrupts the user to gather a response. - **drawer** — A bottom sheet that can be dismissed by dragging it down. - **dropdown-menu** — A menu of actions revealed from a trigger, with submenus and selectable items. - **gooey-popover** — A round trigger whose popover pours out of it, melted together by an SVG goo filter. _(beta)_ - **morph-surface** — A dock that grows in place into a panel — a feedback form or a quick prompt — and shrinks back when done. _(beta)_ - **popover** — Rich floating content anchored to a trigger. - **rich-popover** — A popover card for an inline reference — heading or link, description, a meta chip and one call to action. _(beta)_ - **sheet** — A panel that enters from an edge of the viewport for secondary content. - **tooltip** — A short label revealed on hover or keyboard focus. ## Navigation - **breadcrumb** — Where the current page sits in the hierarchy, and how to get back up it. - **browser-tabs** — A miniature browser window whose tabs are a real tablist: a card-coloured leaf springs under the active tab, and tabs reorder by drag or keyboard. _(beta)_ - **canvas-toolbar** — A Figma-style tool rail: one active tool with a springy fill, a shape slot that swaps its tool from a flyout, and single-key shortcuts. _(beta)_ - **command** — A searchable command palette, with groups and a ⌘K dialog variant. - **create-menu** — A DropdownMenu with a morph flourish: a "+ Create" pill that grows in place into its menu panel. _(beta)_ - **focus-blur-links** — A row of links where hovering or focusing one blurs and dims the rest, with an optional dashed bracket. _(beta)_ - **goo-tabs** — Dowel Tabs with a motion flourish: an icon bar whose pill stretches over the old and new tab, then snaps onto the new one, melted together by an SVG goo filter. _(beta)_ - **magnify-dock** — A macOS-style dock whose icons grow, lift and show a label as the pointer or keyboard focus passes over them. _(beta)_ - **pagination** — Navigation between pages of a list. - **radial-menu** — A round button whose options fan out along an arc: press and drag onto one, click, or walk the ring with the keyboard. _(beta)_ - **sidebar** — The application's own navigation: a collapsible rail on a wide screen, an overlay on a narrow one. - **stepper** — A multi-step wizard's progress — connectors fill, finished steps draw a check, and each step's content slides in from the side it comes from. _(beta)_ - **tabs** — Switches between panels of related content. ## Display - **action-node** — A workflow node card whose round action buttons spring out in an arc around its top-end corner on hover or from a More actions trigger. _(beta)_ - **aspect-morph** — A picture that smoothly reshapes between aspect ratios, picked from a segmented control with a sliding thumb. _(beta)_ - **avatar** — An image representation of a user or entity with a graceful text fallback. - **avatar-group** — Overlapping avatars that spread apart on hover or keyboard focus, collapsing the rest into a "+N" count. _(beta)_ - **badge** — A compact marker for status, counts and categories. - **book** — A 3D book cover drawn in CSS that tilts, or swings open to reveal its first page, on hover and keyboard focus. _(beta)_ - **card** — A surface that groups related content and actions into a single block. - **card-spread** — A stack of cards that fans into an arc, row, corner fan, stamp arc, cascade, dealt hand or wheel on hover, focus or click. _(beta)_ - **card-stack** — A pile of cards you step through as a receding deck, or that fans out into an arc on hover and focus. _(beta)_ - **carousel-3d** — A 3D carousel of cards — a fanned arc or a CoverFlow path — with buttons, dots, arrow keys and swipe. _(beta)_ - **comment-bubble** — A canvas comment pin — an avatar in a speech-bubble corner that grows into the thread and a reply composer. _(beta)_ - **expandable-cards** — Cards that open into a detail view — widening in place in a row, or growing out of a grid into a modal. _(beta)_ - **expandable-list** — A list of compact rows — jobs, releases, people — each growing into a detail dialog out of its place in the list. _(beta)_ - **glow-card** — Card surfaces with a soft glow that follows the pointer, alone or continuously across a group. _(beta)_ - **image-accordion** — Image panels in a row — the open one widens and shows its caption, the rest stand as narrow strips — opened by hover, focus or press. _(beta)_ - **image-metadata** — An image with a row of actions and a details button that opens a metadata panel, lifting the image to make room. _(beta)_ - **invite-carousel** — Event invitations fanned out as tilted cards — the current one upright in front, its neighbours leaning behind — advancing on a timer or by hand. _(beta)_ - **island** — A pill that morphs between views — idle, a call, a timer, a player — resizing around whatever it shows. _(beta)_ - **marquee** — Scrolls its children in a seamless, endless loop — horizontal or vertical, at a set speed, pausing on hover and focus. _(beta)_ - **now-playing** — A compact music mini-player that expands in place, with a morphing play button, a like and a seek slider. _(beta)_ - **number-flow** — A number whose digits roll to each new value — counters, prices, percentages and compact figures, formatted by Intl.NumberFormat. _(beta)_ - **photo-stack** — A pile of photos: flick the top one away and it springs to the back, or tap, key or button through them. _(beta)_ - **photo-tabs** — A photo with a floating bar of icon tabs; each tab swaps the photo. _(beta)_ - **pixel-avatar** — A deterministic pixel avatar generated from a seed — crisp SVG, coloured from theme tokens, with a gentle shimmer. _(beta)_ - **product-card** — A shop tile with image zoom, badge, half-star rating, discount pricing, a wishlist toggle and an add-to-cart confirmation. _(beta)_ - **reviews-carousel** — Testimonials stacked in depth — the active review in front, the next ones receding behind — stepped through with buttons, indicators or arrow keys. _(beta)_ - **star-count** — An animated star counter — plain or as a star button — with the stargazers' avatars beside it. The count is a prop; nothing is fetched. _(beta)_ - **swipe-carousel** — Cards on a ring seen from the front — swipe, tap or step and the ring turns, so nothing ever leaves the frame. _(beta)_ - **switchboard-card** — A feature card illustrated by a grid of tiny lights — a lit pattern such as a word, or random flicker. _(beta)_ - **tilt-card** — A card that tilts in 3D toward the pointer, with a glare that follows it and layers that float at their own depth, springing back flat on leave. _(beta)_ - **time-stack** — Cards receding in depth, stepped through with a timeline scrubber, the mouse wheel or the arrow keys. _(beta)_ - **todo-tower** — To-do cards stacked like bricks: tick one and it flicks away as the cards above drop; drag one and the stack sways. _(beta)_ - **tweet-card** — A social post drawn from props — author, text, photos, date and counts — with a link out to the original. No network, no embed script. _(beta)_ ## Data - **accordion** — Vertically stacked sections that expand to reveal their content. - **activity-feed** — A chronological list of events, with a connecting timeline rail. - **code-block** — A block of code with a copy control, ready for any highlighter. - **contribution-graph** — A GitHub-style year heatmap of daily counts — a keyboard-navigable grid with a tooltip per day. _(beta)_ - **data-table** — Presentation for a TanStack Table instance: sorting, column visibility and pagination. - **diff-viewer** — A diff you can style, and accept or reject hunk by hunk. - **dither-area** — An area chart filled with dithered cells over a cell grid, with a date scrubber that swells the cells around it. _(beta)_ - **dither-bar** — Stacked bars drawn in dithered cells that grow on change, with series highlighting on hover and a per-column readout. _(beta)_ - **dither-canvas** — The engine behind the dither charts: a DPR-capped, self-pausing canvas loop, token colours, a deterministic cell hash, springs, geometry and a keyboard scrubber. _(beta)_ - **dither-donut** — A donut chart drawn in shimmering dithered cells, with wedges that pop out and sparkle on hover, focus or pin. _(beta)_ - **dither-funnel** — A conversion funnel of dithered stage bars that morph between periods, with overall and step conversion per stage. _(beta)_ - **dither-gauge** — A half-circle gauge drawn in dithered cells, one sweeping ring per metric, with a centre reading and metric switch. _(beta)_ - **dither-heatmap** — A rows × columns intensity grid drawn in dithered tiles that morph between periods, with a keyboard-navigable cell readout. _(beta)_ - **dither-line** — A smooth monotone line over a drifting dithered gradient fill, with a keyboard-operable point scrubber. _(beta)_ - **dither-meter** — A capacity bar drawn in dithered cells, split into categories that fill with a spring, with a category legend. _(beta)_ - **dither-scatter** — A bubble scatter drawn in dithered cells: floating bubbles sized by value that glide between data sets, with a per-point readout. _(beta)_ - **dns-record** — Add this record at your provider: parts copied separately, checked with what was found. - **log-viewer** — A streaming console with filtering, level facets and follow mode. - **metric-delta** — A headline number with a change indicator that knows which direction is good. - **permission-matrix** — Roles across, permissions down, with inheritance, locked roles and one tab stop. - **record-diff** — Field-level before and after, for audit entries, settings history and revisions. - **table** — Semantic table primitives for tabular data. - **tick-progress** — A percentage drawn as a row of waveform ticks under a big figure — a progress bar, or a slider with hover preview. _(beta)_ - **uptime-matrix** — A day-by-day status history drawn in dithered tiles — operational, degraded, outage — with a keyboard-navigable readout and legend. _(beta)_ ## Feedback - **alert** — A callout that draws attention to an important message. - **bar-loader** — Indeterminate loading indicators made of bars — cascade, equalizer, wave physics, an indeterminate sweep and 17 more motions. _(beta)_ - **dots-loader** — Indeterminate loading indicators made of dots — pulse, bounce, ripple, orbit and 21 more motions. _(beta)_ - **empty-state** — Shown where content would be, explaining why it is empty and what to do next. - **grid-loader** — Indeterminate loading indicators on a grid of cells — 48 patterns (and 17 SmoothUI alias names) that pulse or stagger, plus sequence, thinking and matrix. _(beta)_ - **meter** — A measurement against a capacity — quota, seats, spend — segmented by category. - **notification-badge** — A dot, rolling count or presence badge pinned to the corner of an icon, button or avatar. _(beta)_ - **progress** — Shows how far along a task is, or that one is running at all. - **pull-to-refresh** — A sheet you pull down to refresh, with rubber-band resistance, a dot ring that fills as you pull and springs that carry the pull's velocity. _(beta)_ - **ring-loader** — Indeterminate loading indicators made of rings and spinners — classic, sweep, radar, gears and 26 more motions. _(beta)_ - **session-expiry** — The idle-timeout warning WCAG 2.2.1 asks for: warned, extendable, and not dismissable by accident. - **shape-loader** — Indeterminate loading indicators made of geometric shapes — flipping squares, hexagons, hourglasses, hearts and 31 more motions. _(beta)_ - **skeleton** — A shaped placeholder that holds layout while content loads. - **spinner** — An indeterminate loading indicator for buttons, panels and inline content. - **sync-status** — Offline, saving, saved or failed — with the count of changes being held. - **text-loader** — Indeterminate loading indicators made of words and interface shapes — shimmer, typing, skeleton, terminal and 15 more motions. _(beta)_ - **toast** — Brief, non-blocking messages with an imperative API callable from anywhere. ## Layout - **collapsible** — A single section that opens and closes, without an accordion's set semantics. - **separator** — A horizontal or vertical rule that divides content. ## AI - **ai-action-ledger** — What an agent actually did, classified by what can be undone. - **ai-agent-plan** — What an agent intends to do — including when it changes its mind mid-run. - **ai-agent-status** — A pill showing what an agent is doing, in words as well as colour. - **ai-approval-request** — Approve a tool call — after correcting the arguments the model got wrong. - **ai-artifact** — A titled frame for something the model produced, with preview and code panes that slide along one axis and a copy action. _(beta)_ - **ai-branch** — Alternative versions of a conversation turn — regenerated answers, edited prompts — with a wrapping pager between them. _(beta)_ - **ai-conversation** — The scrolling transcript container, with follow-on-new-content and a status region. - **ai-disclosure** — Tells a reader they are looking at AI, and what is actually known about it. - **ai-extraction-review** — Check extracted fields against the document they came from, and decide each one. - **ai-inline-completion** — Ghost-text suggestion inside a real textarea, accepted with Tab. _(beta)_ - **ai-loader** — A labelled AI waiting indicator — thinking dots, an indeterminate bar or a thinking grid — with an optional elapsed-seconds counter. _(beta)_ - **ai-message** — One turn in a conversation, with role, avatar, actions and footer slots. - **ai-model-selector** — Picks the model a conversation runs on, with descriptions and availability. - **ai-prompt-input** — The composer: auto-growing textarea, send-on-Enter, and a send/stop control. - **ai-reasoning** — A collapsible disclosure for the model's reasoning. - **ai-response** — Assistant response text, with a streaming caret and a thinking indicator. - **ai-sources** — Inline citation markers and the source list they refer to. - **ai-structured-output** — An object arriving field by field from the model, without the layout jumping. - **ai-suggested-value** — An AI-proposed value for any form control, pending until accepted and marked afterwards. - **ai-suggestions** — Prompt suggestion chips for a chat's empty state or follow-ups, arriving from the centre of the row outwards. _(beta)_ - **ai-token-usage** — A gauge showing how much of the context window a conversation has used. - **ai-tool** — A collapsible record of a tool the model called, its arguments and its result. - **command-bar** — A compact one-row prompt bar — auto-growing field, dictate toggle and send — composed from AI Prompt Input. _(beta)_ - **orb-face** — A cartoon assistant orb whose gaze follows the pointer, who blinks, and whose expression tells its state — listening, thinking, speaking, done or broken. _(beta)_ ## Effects - **cursor-follow** — A dot that trails the pointer on a spring inside a container and swells into a label over marked elements. _(beta)_ - **escape-button** — A novelty button that scoots away from an approaching mouse, then gives up after a few escapes. _(beta)_ - **folding-frame** — A photo folded shut like a book in 3D — drag across it (or use the keys) to open the cover until it lies flat. _(beta)_ - **glass-bubble** — A draggable glass lens that refracts the content under it, with a specular highlight and chromatic fringing. _(beta)_ - **goo-ball** — A decorative jelly ball you drag around a well: it stretches along its velocity and squashes against the walls. _(beta)_ - **gradient-orb** — An animated gradient orb — a rotating conic mesh with a dot screen, sheen and bloom — that can follow an AI state and a live audio level. _(beta)_ - **palette-generator** — A row of swatches that melt together through a goo filter and pop back out in a new palette. _(beta)_ - **scramble-text** — Text whose characters churn through random glyphs and resolve from the inline start, on hover, focus, mount or view. _(beta)_ - **scroll-reveal-text** — A paragraph whose words brighten from dim to full as it scrolls through the viewport. _(beta)_ - **shader-transition** — Transitions a frame between two states under a full-frame WebGL reveal — one raw-WebGL engine and sixteen presets (aperture, chroma, prism, SDF blobs and circles, noise, wipe, stripes, spiral…). _(beta)_ - **shimmer-text** — Text with a light band sweeping across it on a loop, or a blur-and-glide entrance as it arrives. _(beta)_ - **text-effect** — Text that animates in by character, word or line — blur, rise, mask, spring, centre-out, phrase builds and a wave, as 19 presets. _(beta)_ - **text-swap** — Text that animates from the old string to the new one when its value changes — fade through, shared axis X/Y/Z and per-word crossfade — with a TextRotate for cycling phrases. _(beta)_ - **typewriter-text** — Types text a character at a time behind a blinking caret — once, on a loop, or cycling through a list. _(beta)_ ## Blocks Whole sections. Installing one installs every component it is built from. - **admin-dashboard** — An administration console: the shell every admin page shares — navigation, breadcrumb, account menu — and the overview that is its front page, with what needs attention first. _(resolves 11 components)_ - **admin-users** — A team administration table with filtering, sorting and per-row actions. _(resolves 8 components)_ - **agent-console** — One agent run, watched: the plan it is working from, the approval it is blocked on, and the ledger of what it has already done. _(resolves 8 components)_ - **ai-chat** — A complete chat surface: transcript, reasoning, tool calls, sources and composer. _(resolves 11 components)_ - **ai-dashboard** — What the AI features cost and whether they worked: tokens, spend, failure rate, a breakdown by model, and the runs still going. _(resolves 6 components)_ - **ai-workspace** — A whole AI application surface: conversations down one side, the active transcript with reasoning, tool calls and sources in the middle, and the context — window usage, attachments and a structured result — on the other. _(resolves 13 components)_ - **analytics** — An analytics page: headline metrics against the previous period, a series over time, and the breakdown that made it up. _(resolves 5 components)_ - **billing** — A billing page: the current plan, metered usage against its limits, the payment method and the invoice history. _(resolves 6 components)_ - **command-center** — Operations at a glance: service health worst-first, open incidents by severity, capacity meters, a filterable log stream, and a command palette for every action an operator reaches for. _(resolves 8 components)_ - **crm** — A sales pipeline: open value by stage, the deals in it with filtering and sorting, the win rate and cycle length, and the last few touches. _(resolves 12 components)_ - **cta-banner** — A compact banner call to action: headline, one line of copy and a single action. _(resolves 2 components)_ - **cta-centered** — A centred call to action with two actions on a muted band with a soft glow. _(resolves 1 components)_ - **cta-split-image** — A two-column call to action whose copy and image slide in from either side. _(resolves 1 components)_ - **dashboard** — An overview page with headline metrics and a recent activity feed. _(resolves 4 components)_ - **faq-accordion** — Frequently asked questions as bordered cards, one answer open at a time. _(resolves 1 components)_ - **faq-categorized** — Frequently asked questions in topic tabs, each topic an accordion of answers. _(resolves 2 components)_ - **faq-searchable** — Frequently asked questions filtered by a search field as you type. _(resolves 3 components)_ - **faq-tabbed-grid** — Frequently asked questions in category tabs, each category a grid of always-visible answers. _(resolves 1 components)_ - **features-alternating** — Feature rows that alternate copy and media from side to side, each sliding in from its own side as it scrolls into view. - **features-bento** — A bento grid of features: a two-by-two lead cell carrying a visual — by default a small analytics panel whose bars grow in — among smaller cells. _(resolves 2 components)_ - **features-icon-grid** — A features section: a grid of cards, each an icon, a title and a sentence, rising into view as the page scrolls. _(resolves 1 components)_ - **footer-mega** — A mega footer: logo, four link columns and a newsletter sign-up, over a copyright and social bar. _(resolves 3 components)_ - **footer-minimal** — A one-row footer: logo and copyright, a few links, and social links. - **footer-newsletter** — A site footer with a newsletter sign-up and social links beside four columns of links. _(resolves 3 components)_ - **footer-simple** — A site footer with the brand and social links beside three columns of links. - **forgot-password** — A password reset request, with a confirmation that does not leak account existence. _(resolves 5 components)_ - **hero-grid** — A centred hero over a grid of squares that light up under the pointer. _(resolves 2 components)_ - **hero-minimal** — A quiet hero: a headline whose letters draw together, one line of copy and a text link. _(resolves 1 components)_ - **hero-perspective-grid** — A centred hero over a tilted 3D plane of tiles that light up under the pointer. _(resolves 2 components)_ - **hero-product** — A centred hero with an announcement, headline and two calls to action over a large product screenshot. _(resolves 3 components)_ - **hero-split-image** — A two-column hero with a headline, reviewer avatars, a star rating and calls to action beside an image. _(resolves 3 components)_ - **hero-spotlight** — A dark hero lit by a spotlight beam that opens as it scrolls into view. _(resolves 1 components)_ - **login** — A sign-in form with validation, social providers and a busy state. _(resolves 7 components)_ - **logo-cloud-simple** — A heading, a line of copy and a still grid of customer logos, dimmed until hovered or focused. - **logo-grid-tooltips** — A panel of grayscale logos that lift into colour and name themselves in a tooltip on hover or focus, in three to six columns. _(resolves 1 components)_ - **logo-links-marquee** — A heading over an endless row of large, linked logos that pop in one after another and tilt on hover, with a pause control. _(resolves 2 components)_ - **logo-marquee** — A heading over a quiet, dimmed marquee of logos with a named speed, a direction and a pause control. _(resolves 2 components)_ - **onboarding** — A setup checklist: what is done, which step is current, and what is blocked and why. _(resolves 4 components)_ - **pricing** — A pricing section with plan cards and a monthly/yearly toggle. _(resolves 5 components)_ - **pricing-single-plan** — One plan with every feature, under a monthly/annual switch with a price that rolls. _(resolves 6 components)_ - **pricing-three-tier** — Three plans side by side, the middle one featured, under a monthly/annual switch with prices that roll. _(resolves 6 components)_ - **pricing-two-tier** — A free plan beside a featured paid one, under a monthly/annual switch with prices that roll. _(resolves 6 components)_ - **settings** — A settings page with a profile form, immediate toggles and a danger zone. _(resolves 10 components)_ - **signup** — An account creation form with a password strength hint and terms acceptance. _(resolves 6 components)_ - **stats-grid** — A heading over a row of big figures, each with a label and a line of context, whose digits roll up from zero as the row scrolls into view. _(resolves 2 components)_ - **stats-trend-cards** — Metric cards with an icon, a figure that rolls up from zero, a label, a line of context and a trend stated in words. _(resolves 3 components)_ - **team-carousel** — A large two-tone heading over a swipeable carousel of team member cards — avatar, name, role and a line under a divider — with previous and next buttons. _(resolves 3 components)_ - **team-grid** — A heading over a grid of team members — a large portrait, name, role, location and bio — rising in one after another. _(resolves 1 components)_ - **testimonial-rotator** — One large quotation at a time, rotating on a timer shown by a filling indicator, with a stop/start control. _(resolves 2 components)_ - **testimonial-spotlight** — A heading beside one testimonial at a time, stepped through with previous and next. _(resolves 3 components)_ - **testimonial-star-grid** — Reviews in a grid, each with a star rating, the quotation and its author. _(resolves 1 components)_ --- # Dowel — AI components 24 surfaces for AI features. Reach for these before building anything custom for a model-facing interface. Most component sets ship a chat transcript and stop. Real AI features are extraction, enrichment, autofill and agents that *change things* — so the parts that matter are the ones around the transcript, not the transcript itself. - **ai-action-ledger** — What an agent actually did, classified by what can be undone. - **ai-agent-plan** — What an agent intends to do — including when it changes its mind mid-run. - **ai-agent-status** — A pill showing what an agent is doing, in words as well as colour. - **ai-approval-request** — Approve a tool call — after correcting the arguments the model got wrong. - **ai-artifact** — A titled frame for something the model produced, with preview and code panes that slide along one axis and a copy action. - **ai-branch** — Alternative versions of a conversation turn — regenerated answers, edited prompts — with a wrapping pager between them. - **ai-conversation** — The scrolling transcript container, with follow-on-new-content and a status region. - **ai-disclosure** — Tells a reader they are looking at AI, and what is actually known about it. - **ai-extraction-review** — Check extracted fields against the document they came from, and decide each one. - **ai-inline-completion** — Ghost-text suggestion inside a real textarea, accepted with Tab. - **ai-loader** — A labelled AI waiting indicator — thinking dots, an indeterminate bar or a thinking grid — with an optional elapsed-seconds counter. - **ai-message** — One turn in a conversation, with role, avatar, actions and footer slots. - **ai-model-selector** — Picks the model a conversation runs on, with descriptions and availability. - **ai-prompt-input** — The composer: auto-growing textarea, send-on-Enter, and a send/stop control. - **ai-reasoning** — A collapsible disclosure for the model's reasoning. - **ai-response** — Assistant response text, with a streaming caret and a thinking indicator. - **ai-sources** — Inline citation markers and the source list they refer to. - **ai-structured-output** — An object arriving field by field from the model, without the layout jumping. - **ai-suggested-value** — An AI-proposed value for any form control, pending until accepted and marked afterwards. - **ai-suggestions** — Prompt suggestion chips for a chat's empty state or follow-ups, arriving from the centre of the row outwards. - **ai-token-usage** — A gauge showing how much of the context window a conversation has used. - **ai-tool** — A collapsible record of a tool the model called, its arguments and its result. - **command-bar** — A compact one-row prompt bar — auto-growing field, dictate toggle and send — composed from AI Prompt Input. - **orb-face** — A cartoon assistant orb whose gaze follows the pointer, who blinks, and whose expression tells its state — listening, thinking, speaking, done or broken. ## Choosing between them - Rendering a conversation → `ai-conversation` with `ai-message` and `ai-response`. - The composer → `ai-prompt-input`, with `ai-model-selector` if the model is switchable. - A tool the model called → `ai-tool`. Its arguments and result belong there, not in prose. - Asking permission *before* a tool runs → `ai-approval-request`. - Reporting what it did *after* → `ai-action-ledger`, which is also where reversibility belongs. A deletion can be undone, a refund can only be offset, a sent email cannot be taken back — the ledger is where that distinction is shown. - An object streaming in field by field → `ai-structured-output`, which reserves layout up front so nothing jumps. - Ghost text in a real textarea → `ai-inline-completion`. Escape always returns Tab to focus management, so a keyboard user is never trapped. - A value the model proposes for a form field → `ai-suggested-value`. - Reviewing what was pulled out of a document → `ai-extraction-review`. - Long-running work → `ai-agent-status` and `ai-agent-plan`. - Where an answer came from → `ai-sources`. Cost → `ai-token-usage`. Chain of thought → `ai-reasoning`. ## Whole surface at once ```bash npx @dowel-ui/cli add ai-chat ``` --- # Dowel — theming Tokens are two-tier. **Tier 1** is raw scales: an OKLCH neutral ramp, a radius ladder, a 15px-base type scale, elevation, motion. **Tier 2** is semantic aliases — `--primary`, `--background`, `--border`, `--ring` — and components consume Tier 2 *exclusively*. Re-skinning the system means reassigning Tier 2. It never means editing a component file. If you find yourself changing a colour inside a component, the change belongs in the token layer instead. ## Presets `default`, `ocean`, `emerald`, `violet`, `rose`, `amber`, `monochrome`, `candy`, `indigo`, `blue`, `red`, `orange`, `green`. ```html ``` `data-theme` selects the preset; the `dark` class selects the mode. They are independent — every preset works in both. `monochrome` is not only a style. It is a standing check that no component uses colour as its only signal, so verify new work under it. ## Two properties that re-proportion everything - `--radius-scale` — one multiplier behind every corner in the system. `1` is the designed default, `0` is fully square. - `--motion-scale` — one multiplier every duration derives from. Under `prefers-reduced-motion` it collapses, but indicators that report ongoing state are *slowed* rather than stopped via `--motion-scale-indicator`, because a frozen spinner reads as a hung application. ## Contrast All semantic pairs are verified against WCAG 2.2 AA across both modes and every preset, in CI. A new token pair has to pass the same check — do not introduce one without running `audit:contrast`. --- # Per-component detail ## Accordion `accordion` Vertically stacked sections that expand to reveal their content. - Category: Data · Status: stable - Install: `add accordion` - npm: radix-ui - Accessibility: Each trigger is a button inside a heading, so screen reader users can navigate the sections by heading. aria-expanded and aria-controls tie the trigger to its panel, and arrow keys move between triggers. ## Account Menu `account-menu` An avatar that opens an account panel of collapsible sections — edit the profile, check recent orders. - Category: Overlays · Status: beta - Install: `add account-menu` - Also installs: avatar, button, input, label, popover, progress - Accessibility: The avatar trigger is named "Account menu for " and opens Dowel's Popover: a role="dialog" labelled by the user's name, with focus moved inside, Escape and outside-press dismissal and focus returned to the trigger. It is deliberately not role="menu": sections contain form fields. Each section is a disclosure button (aria-expanded, aria-controls) revealing a named region that is inert while collapsed. Form fields are labelled; order progress bars and view buttons name their order. Transitions stop under reduced motion. ## Action Node `action-node` A workflow node card whose round action buttons spring out in an arc around its top-end corner on hover or from a More actions trigger. - Category: Display · Status: beta - Install: `add action-node` - Also installs: avatar, tooltip - npm: class-variance-authority - Accessibility: Hover opens the fan, and so does the "More actions" trigger (aria-expanded, aria-controls), which is revealed on hover and keyboard focus and always shown on devices without hover. Enter, Space or ArrowDown on it open the fan and focus the first action. The fan is role="toolbar" (named by toolbarLabel) with a roving tab stop: the arrow keys move along the arc (Left/Right mirrored in right-to-left layouts) with wrap-around, Home/End jump to the ends, and Escape closes it and returns focus to the trigger. Closed, the fan is inert and aria-hidden, so tucked buttons are neither focusable nor announced. Every action is an icon button named by aria-label and repeated in a tooltip. The hover bridge is aria-hidden; the springs are CSS transitions that settle at once under reduced motion. ## Activity Feed `activity-feed` A chronological list of events, with a connecting timeline rail. - Category: Data · Status: stable - Install: `add activity-feed` - npm: radix-ui - Accessibility: An ordered list, so position and count are announced — the order is the meaning here. The rail and the indicators are decorative; the item text has to say what happened. ActivityTime requires a machine-readable dateTime, because a relative label like "2 hours ago" is ambiguous outside the moment it was rendered. ## AI Action Ledger `ai-action-ledger` What an agent actually did, classified by what can be undone. - Category: AI · Status: stable - Install: `add ai-action-ledger` - npm: class-variance-authority, radix-ui - Accessibility: Reversibility is stated in words on every entry, never by colour or icon alone — it decides whether the undo control means anything, so it cannot be decoration. Selection uses native checkboxes with real labels, and the revert button carries the count in its accessible name so it says what pressing it will do. The selection summary is an aria-live region because the wording changes as the choice changes, and warns before the click when something can only be offset rather than undone. ## AI Agent Plan `ai-agent-plan` What an agent intends to do — including when it changes its mind mid-run. - Category: AI · Status: stable - Install: `add ai-agent-plan` - Accessibility: An ordered list, because a plan is a sequence and the order carries meaning an unordered list would discard. The running step carries aria-current="step", which marks the reader's place without moving focus and fighting anyone reading ahead. Every status is stated in text as well as drawn, and the markers are aria-hidden so the status is not heard twice per step. The live region reports structural revisions only — announcing every status transition would talk over the reader continuously on a plan of any length. Drawn checks and crosses live inside the hidden markers; quietCompleted dims finished steps with a contrast-audited token, and the optional sweep is decoration that stops under reduced motion. ## AI Agent Status `ai-agent-status` A pill showing what an agent is doing, in words as well as colour. - Category: AI · Status: stable - Install: `add ai-agent-status` - npm: class-variance-authority - Accessibility: The state is always text. Agent states matter most when something has failed, which is exactly when a colour-only signal fails the people who most need to see it. Live announcements are off by default — several agents each announcing their transitions turns a dashboard into noise; enable it for the one agent being watched. ## AI Approval Request `ai-approval-request` Approve a tool call — after correcting the arguments the model got wrong. - Category: AI · Status: stable - Install: `add ai-approval-request` - Accessibility: The proposed arguments are a description list of real labelled form controls, so each value is associated with its name and editable ones are reachable by keyboard. A corrected argument is marked in text rather than by border colour alone, because an audit trail has to distinguish the model's proposal from the human's edit. The request is aria-busy while arguments are still arriving and the decision controls stay disabled until it is whole — rendering nothing until then, as the common implementation does, means nothing is on screen at the moment approval becomes relevant. Irreversibility is stated as a sentence, never as a severity colour. Focus never falls to the page as controls swap: deciding moves it to the outcome (tabindex -1, never a Tab stop), Deny… moves it into the reason field and Back returns it — but only when focus was already inside, so a replayed or remote decision never steals it (manageFocus={false} opts out). ## Artifact `ai-artifact` A titled frame for something the model produced, with preview and code panes that slide along one axis and a copy action. - Category: AI · Status: beta - Install: `add ai-artifact` - Also installs: copy-button, tabs - Accessibility: A group named by its title. With both panes it is a real tablist (arrow keys move between Preview and Code, each panel focusable and named by its tab); with one code pane, the scrolling source is a focusable region named by the title. Copying announces success and failure through Copy Button. The pane slide mirrors in right-to-left layouts, never plays on mount, and stops under reduced motion. ## Branch `ai-branch` Alternative versions of a conversation turn — regenerated answers, edited prompts — with a wrapping pager between them. - Category: AI · Status: beta - Install: `add ai-branch` - Also installs: button - npm: class-variance-authority - Accessibility: The pager is a group named "Versions" with real Previous/Next buttons (their chevrons mirror in right-to-left layouts) and a polite, atomic "2 of 3" indicator, so paging says where it went. Inactive versions are hidden rather than unmounted, keeping their state. The pager disappears when there is only one version. The entrance is decoration and stops under reduced motion. ## AI Conversation `ai-conversation` The scrolling transcript container, with follow-on-new-content and a status region. - Category: AI · Status: stable - Install: `add ai-conversation` - Accessibility: The transcript is an ordered list, NOT a live region. A live region that updates on every streamed token is unusable with a screen reader, and is the most common accessibility failure in chat interfaces. Announce state — "generating", "response complete" — through ConversationStatus instead, and let the reader navigate the transcript at their own pace. Auto-scroll stops the moment the reader scrolls up, and ConversationScrollButton is the explicit way back. ## AI Disclosure `ai-disclosure` Tells a reader they are looking at AI, and what is actually known about it. - Category: AI · Status: stable - Install: `add ai-disclosure` - Also installs: popover - npm: class-variance-authority - Accessibility: The text is the disclosure and the icon is decoration, marked aria-hidden — a sparkle alone is a mark a sighted reader may not decode and a screen reader passes over in silence, which is the exact failure this component exists to prevent. Each of the four kinds carries wording of its own, so the distinction between generated, manipulated and human-reviewed survives for anyone who cannot see the styling. The provenance panel states in words whether anyone checked the claims and who, rather than implying it with a tick, and its three states are told apart by their sentences rather than by colour. Scope: this renders the human-visible disclosures of EU AI Act Article 50(1) and 50(4). It cannot satisfy 50(2), which requires machine-readable marking inside the artifact by whoever generated it, and no React component can. Not legal advice. ## AI Extraction Review `ai-extraction-review` Check extracted fields against the document they came from, and decide each one. - Category: AI · Status: stable - Install: `add ai-extraction-review` - Accessibility: Every field quotes its evidence in text under the value, so a reviewer who cannot see the highlight in the source still has what the model read. A value with no evidence is said in words — never left to look like a good one. The source is a focusable named region because it scrolls, and its highlights are mark elements with nothing spliced into the text, since a document read aloud with field names inserted is no longer the document. Focus anywhere in a field brings its evidence into view without moving focus, so a keyboard user is shown the source rather than sent into it. Each control's name carries the field it belongs to, so ten Accept buttons are ten different buttons. Status is a word, outside the label so editing never renames the control, and the running count is a polite live region present from the start. Enter accepts, except while an IME is composing. ## AI Inline Completion `ai-inline-completion` Ghost-text suggestion inside a real textarea, accepted with Tab. - Category: AI · Status: beta - Install: `add ai-inline-completion` - Accessibility: No WAI-ARIA pattern covers generative ghost text — combobox is the nearest and does not fit, because the suggestion is not one of a known set of options and a listbox would misdescribe it. So the suggestion is announced through a polite live description that names the keys, since a gesture nobody knows about is not an affordance, and the grey text itself is aria-hidden. Escape always dismisses and restores plain Tab, so the keyboard is never trapped in the field. The ghost hides during IME composition and whenever the caret is not at the end, rather than rendering somewhere it does not belong. ## AI Loader `ai-loader` A labelled AI waiting indicator — thinking dots, an indeterminate bar or a thinking grid — with an optional elapsed-seconds counter. - Category: AI · Status: beta - Install: `add ai-loader` - Also installs: bar-loader, dots-loader, grid-loader - npm: class-variance-authority - Accessibility: The root is a single role="status" region announcing the label (or `srLabel`, "Loading" by default). The loader inside it and the elapsed counter are aria-hidden — a counter ticking ten times a second inside a live region would announce continuously. The loaders are indicators: under reduced motion they slow rather than stop. None fakes determinate progress. ## AI Message `ai-message` One turn in a conversation, with role, avatar, actions and footer slots. - Category: AI · Status: stable - Install: `add ai-message` - npm: class-variance-authority, radix-ui - Accessibility: Every message carries a visually hidden label naming the speaker. Alignment and colour tell a sighted reader who is talking and tell a screen reader user nothing, so the role is always in text. Message actions fade in on hover but stay in the DOM and in the tab order — a control that only exists on hover is unreachable by keyboard and invisible on touch — and on devices that cannot hover they are always shown. MessageTimestamp is a real