Repository navigation
Releases: aqkprogrammer/dowel-ui
Release list
0.14.0
Added
-
shader-background(experimental): a full-bleed WebGL scene behind
content. One engine draws fourteen procedural presets:dunes,hills,
storm-sea,meadow,petals,glass-wave,liquid-metal,silk,
mesh-gradient,topography,particle-ocean,nebula,warpand
helix.colorsre-dresses any scene with theme tokens or CSS colours, and
attach="viewport"pins it behind a whole page without clipping sticky
headers. It stops drawing off-screen and in hidden tabs, shows one still frame
under reduced motion, and falls back to a CSS gradient in the same palette
without WebGL or after a lost context. -
aurora-background,border-beamandcosmic-background. -
Docs:
/docs/backgroundsshows every background in the library live,
with category filters and, for each one, a prompt for a coding agent that is
generated from the same catalogue as the card. -
Docs: manual install tabs on component and block pages, next to the CLI
command. -
Controls on every component page. A Controls toggle beside the live
example sets its props in place and shows the tag as set; the Playground link
carries those props with it. -
Playground links hold the whole configuration: component, example, theme,
mode, radius and every changed prop. Values read from a link are checked
against the control that would have set them — an unknown option is dropped
and a number is clamped to its range. -
Registry: a
controlon each prop (select, boolean, number, text or
colour), derived from the prop's type with its default, and refined by a new
optionalcontrolsfield inmeta.tsfor what a type cannot say (a number's
range). The MCP server'sget_componentshows number ranges. -
Registry:
capabilities.tier—css,motion,canvasorwebgl, the
heaviest technique an item uses counting what it installs with it. Optional in
the schema, so registries built before it still parse. -
carousel: scroll-snap carousel with previous/next, dots, keyboard
steps in reading direction, several items per view and a vertical layout.
Rotation is opt-in and pauses on hover, focus, off-screen and in hidden tabs. -
comparison-slider: two versions of one thing with a draggable,
keyboard-operable divider. -
color-picker: saturation square, hue and alpha, hex/rgb/oklch,
swatches, eyedropper and a live WCAG contrast reading. -
resizable: panels with window-splitter handles, limits and collapsible
panels. -
password-strength: a strength meter and rule checklist for a password
field. -
Hooks in the registry:
use-reduced-motionanduse-in-viewinstall
into the project's hooks folder (dowel add use-in-view), and are exported
from@dowel-ui/reactand@dowel-ui/react/hooks/*. -
pattern-background,interactive-grid,light-beamsand
flow-field: a CSS pattern backdrop (dots, grid, lines, stripes, checker,
grain), a pointer-lit canvas grid with ripples, CSS rays of light, and
particles on a moving current. All four are on/docs/backgrounds, in a new
"Patterns & grids" filter. -
Docs: background pages link to the gallery ("14 looks in Backgrounds"),
deep-linked to the look, and component pages say how a component draws when
it is more than CSS ("Draws on a canvas", "Renders with WebGL"). -
Scroll effects:
scroll-reveal(seven effects, staggered children, and
content that is never hidden unless it will be revealed),parallax,
stacking-cardsandhorizontal-scroll(pinned, driven by the page's own
scroll, a plain scroller without JavaScript or under reduced motion). -
Cursor effects:
image-trailandcursor-spotlight, scoped to their
box, leaving the system cursor alone, and off for touch and reduced motion. -
Text effects:
gradient-text,highlight-text,letter-swapand
proximity-text— each keeps the text as real, readable text. -
Buttons:
effect-buttongains aglitcheffect;Buttongains
press="depth", raised on an edge it sinks into;confetti-buttonbursts
confetti from itself, andburstConfetti()from anywhere. -
Layout:
glow-cardgainsvariant="spotlight", andbento-gridlays out
tiles of mixed sizes. -
Navigation:
navbar(static, sticky or hide-on-scroll — never hidden
while it holds focus — with a mobile menu and a skip link),
navigation-menu(links and mega menus) andbottom-nav(a phone tab bar
with spoken badges). -
AI:
voice-inputrecords, shows level and time, transcribes where the
browser can, and explains a blocked or missing microphone;
audio-visualizerdraws a stream or a level as bars, a wave or an orb;
workflow-graphlays out a pipeline in layers, each step stating its
status;model-comparisoncompares models in a table that marks the best
of each row in words. -
Blocks:
changelog,contact,careers,integrations,api-keys
(each new key shown once, revoking confirmed),site-header(desktop menus
and the mobile list from one list of links), and two heroes over the new
backgrounds,hero-light-beamsandhero-flow-field. Search finds them by
everyday words — "release notes", "jobs", "mega menu", "api keys". -
3D:
cubeturns to show one face at a time — a carousel to assistive
technology, by buttons, arrow keys or drag;image-ringstands images on a
slowly turning ring you can drag;device-mockupdraws a phone, tablet,
laptop or browser around a screenshot or live UI, with an optional tilt. -
WebGL:
globedraws a dotted globe with places and the routes between
them in raw WebGL, listing them for screen readers and falling back to SVG;
model-viewershows a glTF/GLB model people can turn, behind a poster.
threeis an optional peer used only bymodel-viewer, which is not in
the main entry: import it from@dowel-ui/react/model-viewer. -
Visual regression tests.
packages/visual-testsscreenshots every
Storybook story and compares it with the same story on the base branch, in a
new CI workflow. No baseline images are committed: the job builds Storybook
for both commits and captures the baseline from the base build each time. A
pull request that changes how a story looks fails unless it carries the
visual-changelabel. Seedocs/testing/visual-regression.md. It runs
alongsidepackages/browser-tests, which keeps committed baselines for a
curated set of stories. -
A live agent demo, at
/agent-demo. A model operates a small deals page
through the tools the page registers withagent-surface, and the visitor
can take the page back by touching it, hand it back with a note, approve or
decline the one action that cannot be undone, and undo the rest. The model
runs through one narrow endpoint that is off untilANTHROPIC_API_KEYis
set; without it the page plays a scripted run through the same surface. See
RELEASING.mdfor the configuration and what bounds the cost.
Changed
- Registry items can name dev dependencies. An item whose npm dependency
ships no type declarations lists them indevDependencies, anddowel add
installs them with-D, so the project still type-checks — the install
check caughtmodel-viewerfailing without@types/three. The field is
optional: older registries parse, and an older CLI ignores it (and leaves
the types to be installed by hand).dowel doctor, the MCP server and the
docs' manual install steps list them too. - The install check runs in CI.
pnpm install-checkinstalls every
registry item into a new Next.js app with this checkout's CLI and builds it,
on pull requests that touch the library and nightly against the newest
Next.js. - Releases publish from a tag. Pushing
vX.Y.Zruns a workflow that
refuses to continue until the live registry serves that version, publishes
to npm with trusted publishing, and opens the GitHub release from this
file. SeeRELEASING.md. audit:installed-importsfails when two items ship different files under
one name, the cause of the carousel bug fixed in 0.12.0.blast-radiussays a single kind of change plainly: "2 emails will be
created." where it said "2 emails will change: 2 created."
Fixed
Three things the demo showed within minutes of being used by hand, none of
which a unit test could see.
-
agent-surface: the click that takes control is no longer lost. Ticking
a box or typing in a field while the agent held the page took control and
threw the tick or the character away. Control changed in the event's capture
phase, React rendered before the control's ownonChangewas worked out,
and a controlled input was put back to its old value. The agent is still
refused from the instant of the click, and the change now reaches React in
the bubble phase, with the person's handler. jsdom cannot show this, so it
is checked in a browser (agent-surface.browser.spec.ts, run by a job in the
Browserworkflow). -
agent-surface,agent-approvals: a question is withdrawn when the
person takes over. An approval stayed on screen after a take-over, though
approving it could only be refused. The call now ends at once, told that the
person holds the page, andagent-approvalsmoves on to the next request.
The same happens when the caller aborts. -
agent-replayno longer takes the page from the agent. Stepping through
a replay inside a surface counted as taking over. Like the ledger, it is
marked as the agent's own interface. -
Props tables were missing props a component removes from its element with
Omitand then declares itself (BorderBeam'scolor, for one): 120 across
the library, now listed. -
matrix-orbcould run its springs backwards for one frame: the first
frame's clock and the next frame's timestamp can disagree, and the negative
step w...
0.13.1
Fixes for the accessibility problems the real-browser suite found in 0.13.0.
@dowel-ui/react and @dowel-ui/themes only; the CLI, the MCP server, the
registry builder and create-dowel-app are unchanged at 0.13.0. Components
installed as source get these through dowel update.
Fixed
- Status and primary text on their own tints reach 4.5:1 in light mode.
text-destructiveonbg-destructive/10(and the same for success, warning
and info) measured 4.14–4.32:1, and primary text on the soft button's 12%
tint 3.97–4.48:1 in ten of the thirteen presets. The status colours are
darker in light mode (red-5000.577→0.55,green-5000.53→0.515,
amber-5000.55→0.535,blue-5000.545→0.525), as is the light-mode primary
of the default theme and ofamber,blue,candy,emerald,green,
indigo,ocean,orangeandred(by 0.005–0.035, with hover and active
moved by the same step). Dark mode is unchanged. Every such pair now measures
4.52:1 or better in every preset. - The soft button stays readable while hovered and pressed. Its label now
steps toprimary-hoveras the tint deepens, and the pressed tint is 20%
rather than 24%; primary text on the old hover and pressed tints fell to
3.3–4.4:1. The onboarding block's current-step marker uses a 12% tint, like
the soft button, instead of 15%. audit:contrastchecks text on tints. It now measures each status colour
on its own 10% tint and primary text on the soft button's tints, over both
the page and the card, and composites translucent colours the way browsers
paint them (on gamma-encoded channels). It previously blended in linear
light, which reads a 10% tint as darker than it renders and would have
passed these pairs by ~0.3:1.pnpm audit:contrast --verboselists them.- The theme studio checks text on tints too. A colour derived there could
pass every label check and still fail as text on its own tint, as the shipped
presets did; the studio now lists primary on the soft button's tints, light
and dark, alongside the solid states. ai-suggest-mode: removed text is full-strength, marked by its strike-through
and tint. Muted text on the darker destructive tint measured 4.4:1 — found by
the browser suite after the palette change above.SelectinsideFormControlhad no accessible name.FormControl
passes the field's id, description and invalid state to its child, and
Select's root renders no element, so they were dropped and the label
pointed at nothing.Selectnow passes them on to its trigger.Conversation's transcript could not be scrolled by keyboard when the
messages held nothing focusable. It is now a focusable, named region (label,
default "Conversation"), asTable's scroll wrapper already is.ai-loader: the elapsed-time counter is full-strength muted text instead ofopacity-60on muted text (2.4:1).pull-to-refresh: the demo's balance decimals and idle time windows usetext-muted-foregroundinstead of a faded foreground (2.2:1).browser-tabs: the tab strip follows the tone, so an inverted window's inactive tab titles read at 4.5:1 or more instead of 2.1:1.island: secondary text in the demo views is full-strength, notopacity-70, which was 3.34:1 on the primary tone.code-block: the light-mode highlighted-line band is a 4% tint of the page, so syntax colours on it stay at 4.5:1 or more (text-infowas 4.08:1).log-viewer: the Fields toggle is a 24px-tall target instead of 16px; only rows that have one grow, by 2px.image-accordion: a collapsed panel, which is its own trigger, is never narrower than 24px (it could be 16px).reviews-carousel: each pagination dot is a 24 × 24 target instead of 16 × 24; the dot itself is unchanged.command-centerblock: a resolved incident shows an outline severity badge and muted title instead of fading the row, which took the warning badge to 2.8:1.onboardingblock: a blocked step is no longer faded, so its warning badge has the solid fill instead of a lighter one (3.95:1).selection-list: item descriptions were the foreground at 45% (2.9:1); they usetext-muted-foreground(5.3:1 light, 7.4:1 dark), and full-strength text on the inverted fill.slide-to-confirm: the track label, the control's only visible instruction, wastext-foreground/45(2.9:1); it istext-muted-foreground(5.3:1 light, 7.4:1 dark), and the power shimmer only ever brightens it.confirm-typed: the action was faded toopacity-55(2.2–2.5:1) until the text matched; it stays reachable but is nowaria-disabledand drawn in the outline style, with a full-contrast label, until it takes its real variant on a match.animated-checklist: the "Add new task" button was faded toopacity-34(2.1:1) and done tasks toopacity-42(2.7:1); both usetext-muted-foreground(5.3:1), and a done task is shown by its tick and strike-through.calendar: days outside the month, which are selectable, were muted at 50% opacity (2.0:1); they are plaintext-muted-foreground(5.3:1). The root is nowrelative, so the month navigation sits on the calendar rather than at the edges of the page.- Stories: the
agent-data-tableselection column has a header name, the
skeleton loading stories give their label a role to belong to, and the tabs
stories render the panels their triggers point at.
0.13.0
The CLI and the MCP server now work after the install as well as during it,
and coding agents are told which component is right, not only which exist.
- Security. The CLI no longer trusts its registry with the filesystem or
its licence key: paths are confined, keys go only to the registry they were
issued for, and registry dependencies must be npm packages. - The component genome. Every registry item carries its props, whether it
needs a client boundary, whether it animates, and its quality checks; 188
carry guidance on when to use them and what they are confused with. dowel doctor,diff,auditandplan, and the MCP server's
audit_code.plan --modelasks Claude, with your own credentials.- Private registries with per-registry keys, and governance metadata
(owner,since,deprecated). - In the repository: real-browser accessibility over every story, visual
regression, a fresh-app install of every item in CI, and AgentBench, a
harness for measuring whether agent support helps.
Added
- AgentBench (
packages/agentbench, private): a harness that runs the same
prompt in two copies of a project — with Dowel's agent files and MCP server,
and without — and scores both diffs withtsc,dowel audit, invented and
uninstalled imports, recall of expected components, and the jsx-a11y rules.
Ten tasks, a Claude Code adapter, andnoop/referenceadapters that cost
nothing. No run has been published;/agentbenchon the site documents the
method and shows published runs only. - Private registries can require a key. A registry that answers
401gets
one retry with the key stored for it, and no other; a public registry never
receives a key it did not ask for. Keys are stored per registry, so a Pro
licence and a company key coexist.login --registry <url>verifies against
the registry's index when it has no licence endpoint;logout --registry
removes one key;whoamilists them. The MCP server readsDOWEL_TOKENand
DOWEL_TOKEN_REGISTRYfor the same. - Governance metadata: an item can declare
owner,since, and
deprecated(version, reason, replacement). Deprecated items still install;
addandupdatename the replacement,listanddoctormark them, the
MCP server and agent docs warn off them, and the planners skip them. Custom
registries can also declareguidanceandcomposesWith, and the build
rejects any of these naming an item that does not exist. Upstream guidance
that names an item the extending registry cannot serve, such as a Pro block,
is dropped from the inherited copy. dowel plan "<screen>"chooses the blocks and components for a screen you
describe.--modelasks Claude to choose, with your own Anthropic
credentials and the optional peer@anthropic-ai/sdk; whatever it names
that the registry does not have is dropped and reported. Without--model
it uses the built-in planner, which needs nothing.- MCP
audit_codechecks code an agent wrote against the same rules as
dowel audit.get_componentnow says when to use a component, what it is
confused with, whether it needs a client boundary, and every prop its type
declares;search_componentsmatches on what a component is for. - The agent files list each component's guidance under it, and the planners
score it above a description match. create-dowel-appwrites the agent files when it scaffolds.dowel doctorchecks a project's setup and prints a checklist: the
project shape, the import alias againsttsconfig.json, the tokens in the
stylesheet, installed files present, npm packages and component dependencies
installed, a licence for any Pro item, updates available, and stale agent
docs. It is a checklist, not a score, and it writes nothing.dowel diff [names…]shows how installed files differ from the
registry's current ones, as a unified diff.dowel audit [paths…]finds Tailwind palette colours, literal colours in
classes and inline styles, arbitrary sizes off the scale, physical direction
utilities, and native elements where the Dowel component is installed. It
skips the files Dowel wrote.--fixrewrites the physical utilities, the
only findings with one exact fix, after asking.--jsonis for CI.- The component genome. Every registry item now carries
capabilities
(whether it needs a client boundary, whether it animates),propsread from
its type, and thequalitychecks from/quality. Items may also declare
guidance(when to use it, when not, what it is confused with) and
composesWith. All optional: older registries parse, and older CLIs ignore
the new fields. - The registry now publishes the JSON Schemas its
$schemafields pointed at:
r/schema/registry-item.jsonandr/schema/registry-index.json. - The MCP server has contract tests for every tool, and a README.
Continuous integration
- Every Storybook story is checked by axe in a real browser, light and dark,
with thecolor-contrastandtarget-sizerules the jsdom tests cannot
run (packages/browser-tests, ADR 18). It found 140 violations across 82
stories, recorded as 83 entries inknown-violations.json, each with a
reason — 70 of them "to fix". The suite fails on anything new and on any
entry that no longer occurs, so the list can only shrink. The largest group
is status text on its own 10% tint (4.1–4.5:1), a pair the palette audit
never checked. - Visual regression for 42 curated stories — forms, open overlays, data,
feedback, AI and five blocks — in light and dark, LTR and RTL, compared
pixel-for-pixel inside the pinned Playwright container (188 images). It
found the calendar's month navigation anchored to the wrong ancestor. - Storybook has a Direction toolbar global that sets
dirand wraps the
story inDirectionProvider, so RTL previews mirror the primitives too. - Coverage thresholds are enforced in CI (measured: 97.3% statements,
93.4% branches, against floors of 85% and 80%). - Every free item is installed into a fresh app on every pull request
(scripts/smoke/install-all.mjs): scaffold,init,addall of them,
tsc --noEmit,next build— the release check that used to be manual.
Security
- Registry file paths are confined to their directory. A path such as
ui/../../.bashrcused to be written outside the project. The registry
schema now refuses absolute paths,..,.and empty segments,
backslashes, colons and NUL, and the CLI checks again where the path meets
the disk. removeonly deletes what the CLI could have written. It used to delete
any pathcomponents.jsonlisted. It now refuses, deleting nothing, when an
entry names a file outside the directories components are installed into.
Alias directories outside the project, as in a monorepo, still work.- The licence key goes only to the registry it was issued for, over HTTPS.
The registry an install reads comes fromcomponents.json, so a cloned
repository could name its own server, mark an item as licensed, and collect
the key.loginnow records which registry it verified the key against, and
the CLI refuses to send the key anywhere else. Keys stored before this change
belong to the default registry.DOWEL_TOKENbelongs to the default registry
unless the newDOWEL_TOKEN_REGISTRYnames another. - Registry dependencies must be npm package names, optionally with a
version range. Agit+https:URL, a tarball or a local path is refused
instead of being handed to the package manager. - Item names are validated wherever they arrive from, including the
command line, before they become a URL or a file path.
Fixed
remove theme --forcedeleted the project's whole stylesheet, because
initrecords it undertheme. The stylesheet is now never deleted.updatefailed with ENOENT restoring a file whose directory had been
deleted.- Registry and licence requests time out after 30 seconds instead of waiting
indefinitely. - The MCP server's
install_commandsaid a Pro item was "not found"; it now
resolves it from the index and says it needs a licence. Unknown names are
all reported together, with suggestions, and a name like../packageis
refused rather than read from outside the registry. audit:rtlskipped a physical utility whenever a class such asbg-muted
sat within a dozen characters before it. No component had such a bug hiding;
the check is now exact.- The CLI and scaffolder state Node 20.12 as their floor, which their prompts
library requires, and CI runs the built binaries on Node 20 and 22.
0.12.0
Twenty-four animated components from Animate UI's patterns, 244 in all (up
from 220). Also fixes sheet and drawer dimming their own panel, and
swipe-carousel breaking the other carousels when installed after them.
Added
Twenty-four animated components whose patterns come from Animate UI. All are
original implementations: Animate UI's licence (MIT with the Commons Clause)
does not allow redistribution, so none of its code was used. See
THIRD_PARTY_NOTICES.md. Animate UI items Dowel already covered, such as tabs,
tooltip, accordion and the copy, icon and theme-toggler buttons, were not
added again. All 24 are beta, and all of them stop or settle under reduced
motion.
- Overlays:
alert-dialog(springs up out of a blur, and the destructive
tone shakes its icon once),hover-card(grows from its trigger with an
overshoot, and can stagger its contents) andpreview-link-card(a link
whose preview image wipes in from a shimmer; nothing is fetched). - Form controls:
toggle(squishes when pressed, and its fill pours out
from the centre),toggle-group(a sliding highlight in single mode,
per-item springs in multiple mode),flip-button,ripple-button,
liquid-button(rolling liquid fill with an inverting label) and
share-button(opens into a staggered row of targets, including copy-link
and the native share sheet). - Data and navigation:
file-tree(the full ARIA tree pattern, with
folders that tilt open, a drawn guide rail and a gliding selection),
code-tabs(syncKeyswitches every instance on the page together and
remembers the choice),pin-list,management-bar(a floating bulk-actions
toolbar with rolling counts) andradial-nav. - Display and feedback:
flip-card(leans toward the pointer, lifts as it
turns, and a sheen sweeps across),radial-intro(avatars spiral out into
an orbiting ring) andnotification-list(a receding deck that springs open
into a list, with swipe-to-dismiss and an always-available dismiss button). - Backgrounds:
stars-background,gravity-stars-background,
fireworks-backgroundandhole-backgrounddraw through the
dither-canvasengine, so they inherit its DPR cap, pause when off-screen
or in a hidden tab, and take their colours from the theme.
bubble-background,gradient-background(linear, aurora and mesh) and
hexagon-backgroundare CSS-first.
Changed
- Generate and the MCP server find the new components from the words
people use for them — "file explorer", "link preview", "are you sure",
"bulk actions", "fireworks", "honeycomb" and others now reach them. - The components page features
fireworks-background,file-treeand
flip-card. button,badge,label,avatar,input,separatorand
data-tablenow mark their root withdata-slot, like every other
component. They were the exceptions, so tooling that finds a component's
parts in rendered markup — the docs site's "Parts" view on block pages —
could not see them. Adata-slotpassed by the caller still wins, so
wrappers such ascopy-buttonkeep their own.
Fixed
- Installing
swipe-carouselno longer breaksreviews-carouseland
invite-carousel. All three ship acarousel-controls.tsx, but
swipe-carousel's was a shorter copy without the rotation control. Files
install flat, so addingswipe-carouselafter either of the others replaced
the file they import from, and the project stopped type-checking. All three
now ship the same file, and a registry test fails if two items ever ship
different files to the same path. If it happened to you, run
dowel update swipe-carousel. sheetanddrawerno longer dim themselves. Each put its overlay on
--z-overlay(300) and its panel on--z-drawer(200), so the overlay
painted over the open panel — and oversidebar's mobile panel, which is a
sheet. The overlay now shares the panel's drawer layer and comes first in
the portal, so the panel sits above it; a dialog opened from inside a panel
still dims it from the layer above. If you installed either, run
dowel update sheet drawer, or changez-[var(--z-overlay)]to
z-[var(--z-drawer)]on the overlay yourself.
0.11.0
Seven components from the "later" list in docs/plans/agent-operable-ui.md,
WebMCP's exposedTo, and fixes that make every registry item install and
build. The plan is docs/plans/next-components.md. All seven are beta.
Added
provenance-textshows who wrote each part of a paragraph: the person,
an agent or a quoted source, with each author's share. Provenance is hidden
until someone turns it on; when shown, agent and source text differ by
underline shape as well as colour, and screen readers hear who wrote each
marked part.provenanceFromEditkeeps attribution current word by word.nl-filter: type what you want to see ("failed on main took over 5"),
press Enter, and get filter chips you can edit or remove. A plain parser
ships forfield:value,field>3, quoted values and option names; pass
your own, such as a model call, and a newer submission aborts the older
one. Text it cannot read stays in the field as "Not understood: …".memory-inspectorshows what an assistant remembers about the person,
where each memory came from and when it was last used, with search, edit
in place, pin and forget. A forgotten memory disappears at once, and
onForgetis only called when the undo window closes.expression-editor, a formula field with highlighting, autocomplete
for variables and functions, the error shown where it is, and a live
result. It parses and evaluates the expression itself, from an allowlist,
withouteval.quantity-input, a number with a unit (kg/lb, GB/TB, s/min, °C/°F).
Changing the unit converts the amount, min and max are quantities so they
hold in any unit, "5 lb" typed or pasted sets both parts, and numbers are
read and written the locale's way.permission-promptasks for a capability when it is needed ("Claude
wants to read your calendar"): why, what it allows and doesn't, and the
risk in words, with allow once, for this session, always, or not at all.
usePermissionPromptgives an app or agent tool a promise to await, and
remembers session and stored grants.chart-sonifierlets you hear a chart. Each series plays as pitch over
time, and a keyboard slider steps through the points, playing each note and
reading the value, beside a one-sentence summary of the series. Nothing
plays until someone asks, and Pause, Escape and Mute stop it at once.agent-surface:exposedToanddebugging, from the WebMCP draft of
2026-09-26.exposedTolists origins, beyond the page's own, that may see
the tools within the page's frames, on the surface or per tool. The browser
refuses a whole tool over one bad origin, so the page drops those first
and says which in development.
Fixed
-
expression-editorbuilds in apps that target ES2017, as a new Next.js
app does. It used the regular expression flags, which TypeScript refuses
below ES2018.packages/uinow also type-checks at ES2017. Found by
installing every registry item into a fresh app, which all 220 components
and 47 blocks now pass. -
Components installed with the CLI now build. In this repo
@/components/xresolves to a folder'sindex.ts, but an installed project
has no index: the CLI rewrites the import to@/components/ui/x, the main
file. 22 main files exported less than their index, so a project that
installed one of them failed to build:- Every dither chart and
uptime-matriximportedcreateSprings,
ditherFilland more fromdither-canvas, whichdither-canvas.tsxdid
not export. agent-formandagent-approvalsimported theJsonSchematype from
agent-surface.toast(),parseCron,FloatingLabelInput,findSensitiveand other
documented exports could not be imported from their component's file.
Each main file now re-exports what its index does, and the new
audit:installed-importsfails CI when one doesn't. Found by installing
0.10.0 into a fresh Next.js app. - Every dither chart and
-
stream-announcer: NVDA with Chrome no longer re-reads the previous two
sentences with every announcement after the third. The live region used to
drop its oldest sentence while adding the newest, and Chrome then reported
every sentence in it as new. It now fills up to three and then starts over.
Found by the first real NVDA run.
0.10.0
Agent-operable UI: agents can operate your UI and hand it back
Eleven components that let an agent work on the page itself, and let the
person oversee it and take the page back. The plan is in
docs/plans/agent-operable-ui.md and the decisions are in ADR 0015.
Control
agent-surface(experimental) is a region whose actions are registered
as tools withuseAgentTool. Each tool runs the same handler a person's
click runs, and its input is validated in the page. Your own assistant calls
tools throughapiRef; withwebmcp, browser agents can call them too,
throughdocument.modelContext(Chrome and Edge origin trials). Control is
state:shared,agentorperson.- While the person holds control, every call is refused, reads included.
- Irreversible actions need approval; without it they are refused.
- Operating a control while the agent drives takes over, except inside
[data-agent-ui]. - Other libraries already expose component actions over WebMCP. This one is
built around who has control.
control-baton(experimental) shows who has control and lets the person
take over, then hand back with a note. The note is added to the start of the
agent's next tool result. It works inside a surface, or on its own with
holder. We don't know of another component library that ships a reusable
take-over / hand-back control; the pattern comes from agent products such as
ChatGPT agent and Browserbase's live view.
Oversight
-
agent-approvals(experimental) is the approval step, built on
ai-approval-request. The person can correct the agent's arguments before
approving, approve once or for the session, or deny with a reason the agent
is told. Mounting it inside a surface is all the wiring there is, and
requests still waiting when it unmounts are refused. -
agent-ledger(experimental) lists what the agent did, built on
ai-action-ledger. It can undo a call whose tool registered an undo with the
newonUndo, and the agent is told what the person took back. -
blast-radius(beta) shows what an action will change before it runs:
how many things, how, which can't be undone, and a sample by name. For
example: "43 deals will change: at least 3 deleted. At least 2 cannot be
undone." A tool's newpreviewdry run fills it in insideagent-approvals
while the person decides. -
agent-replay(experimental) steps through a finished run, by button,
slider or playback. It shows each call, exactly what the agent was told,
and every take-over and hand-back. -
ai-suggest-mode(beta) is track changes for an agent's edits to text.
Each change is shown in place with its reason and accepted or rejected on
its own. It works from edits or from a whole rewrite. The agent is told what
was rejected, so it doesn't suggest it again.
Privacy
prompt-redactor(beta) checks a prompt before it's sent. Email
addresses, card numbers, IBANs, API keys and phone numbers are named, masked,
and sent as placeholders such as[EMAIL_1]. They're put back locally in
the reply. Card numbers and IBANs are only matched when their checksums
pass, and you can add your own detectors.
Tools for existing components
agent-form(experimental) gives fill, read and submit tools to any
form. Fields, labels, options and errors are read from the form itself.
Values are set through the events typing fires, and submitting goes through
the form's own handler. Passwords, one-time codes and card numbers are never
read or filled. Submitting waits for approval unless you say it can be
undone. Withdeclarative, the form also describes itself to browser agents
through WebMCP's form attributes, and their submits pass the same checks.agent-data-table(experimental) providesuseDataTableAgentTools,
which gives a TanStack table read, sort, search, filter, select and page
tools, each only when the table has that feature. They call the same API as
the table's own controls.
Accessibility
stream-announcer(beta) is an opt-in way for a screen reader user to
hear a streaming response as it arrives. It reads whole sentences only,
pacing them so pause, skip and repeat can still act on the queue. Markdown is
read as prose, and a code block is summarised as its language and line count.
ai-conversation's state-only announcements stay the default.- Screen reader tests.
packages/screen-reader-testsdrives real
VoiceOver and NVDA through Guidepup, in a new CI workflow. A harness project
checks the scenarios themselves without a screen reader, and JAWS has a
manual protocol indocs/testing/screen-readers.md.stream-announcerstays
beta until those runs pass.
Changes to existing components
agent-surfacealso gainspreview,told, acontrolLogof changes of
control, andapi.notify, which tells the agent something with its next
result.ai-approval-requestandai-prompt-inputnow carrydata-agent-ui, so
approving a call or typing to the agent inside a surface never counts as
taking over.ai-action-ledgerno longer keeps a reverted action in its selection, where
it was still counted by "Undo 2 selected".
Known issue, fixed in the registry
Until 2026-09-27, some components added with the CLI did not build in the project they were added to: every dither chart, uptime-matrix, agent-form and agent-approvals, among others. Each imported something its sibling's main file did not export. The registry the CLI reads is fixed, so re-run npx @dowel-ui/cli add <name> --overwrite for anything added before then. 0.11.0 adds a check so it cannot happen again.
0.7.0
The release that puts something up for sale, and fixes the bug that finding out how to sell it uncovered.
Nothing that was free has stopped being free. The registry build now names every block that shipped without a licence and fails the release if any of them changes access.
The Pro catalogue
Four new blocks, all access: "pro". Whole application surfaces rather than page sections:
- crm — a pipeline with its deals. Sales cycle is declared lower-is-better, so a slowing pipeline is not painted green.
- command-center — service health worst-first, incidents by severity, capacity meters, a filterable log stream and a ⌘K palette. The overall status is one sentence, and deliberately not a live region.
- ai-workspace — conversations, transcript, and the model's context beside it: window usage, attachments, a structured result filling in.
- admin-dashboard — the shell an admin area shares, with
childrenfor your own pages, and an overview that puts what needs attention first.
Withheld means the index lists them in full and only the gated route serves their bodies. The docs render their previews from the same stories the tests run; packages/ui no longer ships src/blocks in its tarball.
Sidebar fix
The mobile sheet was mounted whenever the rail was open and hidden with CSS. A modal dialog that CSS hides is still modal: on every desktop, whenever the sidebar was open, the rest of the page was aria-hidden and pointer-events was off on the body. It now mounts only below the breakpoint, with its own open state.
The site
Pricing, a private-registry guide, and a front page that counts itself — components, blocks, average quality from the audits, npm and GitHub figures fetched hourly, and a version badge that no longer claims 0.1.0.
Design tokens for Figma
@dowel-ui/themes reads the same CSS the components use and writes W3C design tokens. One file per preset at /figma/<preset>.tokens.json, and the Theme Studio downloads the same for a preset built there.
Full notes in CHANGELOG.md.