Semantic HTML is the public API, CSS custom properties are the customization API, and one optional script adds interactive behavior. Everything on this page applies to version 1.5.0.
Copy smartwebui.css into your project and link it. Add smartwebui.js when you need interactive behaviors such as tabs, the custom select, dialogs, menus, and toasts. There is no installation, build step, compiler, or dependency.
Components are ordinary semantic HTML with class names. The library works with any server stack. PHP can emit the same markup as any other host — there is no Composer package, PHP extension, or compiler. An optional single-file renderer, smartwebui-surface.php, is included for agent surfaces (PHP 8.0+, no dependencies). Styling holds up before JavaScript loads.
Design choices & tradeoffs
smartwebUI is not a React replacement. It is a trusted UI layer for applications where HTML stays authoritative and agents compose within a catalog — not arbitrary markup.
HTML is the runtime; JSON is the agent wire format
Humans, server templates, and agents can all write semantic HTML with smart-* classes. Alternatively, agents can emit validated JSON surfaces that render to the same HTML through the DOM API — the wire format rejects HTML strings inside JSON, not HTML as a medium. There is no third API — the catalog is a subset of what you can hand-author.
When smartwebUI fits
PHP or server-rendered apps that want polished components without a JS framework
Admin tools, internal dashboards, and agent-built operator interfaces
Progressive enhancement: server first paint → adopt() → live patches
Rich client-side SPAs with complex shared state — React, Vue, or Svelte component ecosystems will feel more natural
Mandated support for legacy browsers or locked-down corporate WebViews — Bootstrap or heavily polyfilled stacks may be required
Teams that need maximum Stack Overflow density and hiring familiarity above agent contracts
Dependency-free means you own the bugs
There is no npm dependency tree to absorb fixes — every picker, upload flow, and patch path is maintained in this website. Release gates and contrast requirements are documented in QUALITY.md; accessibility scope in ACCESSIBILITY.md.
Comparison at a glance
smartwebUI
Bootstrap
React + UI kit
Public API
HTML + design tokens
CSS classes + JS plugins
Components + JSX
Agent contract
Catalog + surfaces
None
Ad hoc per app
Build step
None
None
Yes (bundler)
Browser baseline
September 2024+
Broad legacy support
Depends on bundler targets
Best for
Agent UI, PHP-first, progressive enhancement
General marketing sites
Rich client applications
FAQ
Is this a framework?
No compile step. Optional JavaScript hydrates hand-written HTML. Agent JSON is an optional layer on top — the entire showcase works without it.
Can agents write HTML?
Yes. Agents can output semantic smart-* markup the same way humans do — that is the library’s public API. They can also compose through validated surface JSON, which the agent runtime renders to the same HTML via the DOM API. What surfaces reject is raw HTML strings inside JSON declarations; that boundary keeps generative UI fail-closed. Trusted application code may still use update(..., { html: true }) for its own markup.
Does it work without agents?
Yes. Link smartwebui.css and optionally smartwebui.js. Every component in the showcase is plain markup.
Why only modern browsers?
The library uses the Popover API, native <dialog>, cascade layers, color-mix(), light-dark(), and :has() without polyfills. See browser policy.
Can I use it inside React or Vue?
Possible — mount HTML islands and call hydrate() after render. That is not the primary integration story; expect to manage lifecycle yourself.
Where is the security model documented?
SECURITY.md — agent threat model, CSP guidance, and e-commerce boundaries. Summarized under agent security.
Canonical inventory
HTML is the public API. The agent catalog gives every HTML family a safe declarative path, using the same semantics and progressive enhancement. There is no third API.
The inventories are related but intentionally not identical: 50 authored HTML families and 51 agent catalog entries.
HTML families (50). The component reference numbers 50 families. The showcase shows every family except Payment: foundations 01–15, application patterns 16–36, Carousel 38, collaborative components 39–41, Map 42, Data grid 43, Media player 44, Signature pad 45, Tree 46, Context menu 47, Split pane 48, Filter bar 49, and Notification center 50 (Payment is family 37, shown in the reference and agent demo). Combobox, File, Date & time, Search, Tags, and Confirm keep their own snippets even though they map onto Field or Dialog. Integration-heavy families expose bounded declarative views while credentials, authorized queries, media rights, signer evidence, and legal workflows remain application-owned.
Catalog types (47 + 4). The agent catalog has 47 component types plus 4 layout primitives (Stack, Cluster, Grid, Text). Every HTML family has a catalog path; Conversation and Composer are separate nodes because reading a history and authoring a message have different trust boundaries. Related field and dialog variants remain properties rather than inflated type names.
#
HTML family
Catalog type
—
Icons (foundation, not a numbered family)
Icon
01
Buttons (includes split actions)
Button
02
Fields
Fieldcontrol: input, textarea, select, range, otp, quantity, multiselect, numericrange, rating, color (mask is a property, not a control)
03–05
Choices, Switches, Segmented
Choice, Switch, SegmentedControl
06–15
Cards through Progress
Matching catalog names
16–20
Table, Pagination, Alerts, Form errors, Breadcrumbs
smartwebui-icons.svg is a curated, dependency-free SVG sprite built from Lucide plus 17 popular social-network brands. Its 516 stable names are indexed in smartwebui-icons.json. No npm, icon font, custom element, or build step is required for consumers.
--smart-icon-size accepts any valid CSS size: 17px, 2.4em, 10vw, or clamp(1rem, 4vw, 5rem). Set --smart-icon-stroke to tune line weight. The optional helper creates safe DOM nodes:
Omit label for decorative icons next to visible text; provide it for a meaningful standalone icon. Directional icons flip automatically in right-to-left layouts. External SVG sprites should be served from the same origin for the most reliable browser behavior. A different trusted path can be configured with SmartWebUI.setIconSource().
Use sprite icons—not font glyphs—for interface actions and status marks such as close, search, previous/next, add/remove, overflow, warnings, and ratings. Keep punctuation, mathematical notation, keyboard characters, and prose symbols as text. Icon-only controls still require a textual aria-label; their SVG remains aria-hidden="true".
Customizing
Override design tokens after the stylesheet. Every component reads the same variables, so one override updates the whole interface immediately.
Theme colors are written as light-dark() pairs resolved through color-scheme. Light and dark themes follow the operating system preference automatically; <html data-theme="dark"> forces a theme. Density (data-density="compact") and the Liquid or Minimal materials (data-material="liquid", data-material="minimal") are opt-in the same way.
Library CSS lives in cascade layers. Unlayered host CSS wins. See the token reference for the public variable list and the layer order.
Token reference
Public custom properties on :root. Override these after loading smartwebui.css. Names that start with --_ are private to a component and are not part of the API.
Host CSS should stay unlayered so it wins over every @layer smart.* rule, including Liquid (smart.materials). If you use layers, declare them after the library list: smart.reset, smart.tokens, smart.base, smart.layout, smart.components, smart.materials, smart.utilities.
When overriding --smart-accent or --smart-danger, also set --smart-on-accent and --smart-on-danger so contrast stays AA.
Utilities
Single-purpose classes in @layer smart.utilities — the last layer, so they win over components. Spacing steps reference the --smart-space-* scale, which means compact density and token overrides apply automatically.
Spacing
.smart-p-0….smart-p-8 — padding; .smart-px-* / .smart-py-* for inline / block axes; .smart-pt-* / .smart-pb-* / .smart-ps-* / .smart-pe-* for logical start/end sides. Steps 9–12 remain token-only for page-level spacing.
.smart-m-0….smart-m-8 — margin; .smart-mx-* / .smart-my-* for axes; .smart-mt-* / .smart-mb-* / .smart-ms-* / .smart-me-* for logical sides; .smart-m-auto / .smart-mx-auto / .smart-my-auto for centering
.smart-gap-0….smart-gap-8 — gap for .smart-stack, .smart-cluster, .smart-grid, or any flex/grid host
Layout
.smart-container with .smart-container--sm / --md / --lg — width cap + auto margins (40rem / 56rem / 76rem)
.smart-grid--2 / --3 / --4 — fixed column grids that collapse under 50rem; .smart-span-2, .smart-span-full for cell spans
.smart-span-desktop-2 / .smart-span-desktop-full apply spans only on desktop; .smart-sticky and .smart-sticky-top use the library sticky z-index.
.smart-z-raised, .smart-z-sticky, .smart-z-tooltip, .smart-z-toast, and .smart-z-banner expose the public z-index token scale without hard-coded numbers.
.smart-divider and .smart-divider--vertical create token-driven separators with consistent spacing.
.smart-ratio-1x1 / -4x3 / -16x9 / -21x9 — media boxes; children are stretched to cover. Override the crop with .smart-object-contain / -cover / -fill / -scale-down on the child (logos, screenshots).
Native <figure> / <figcaption> are styled in the base layer — caption tone, size, and spacing come free, no classes.
.smart-control-sm / .smart-control-lg — size any form control by overriding --smart-control-height locally: inputs, selects, date pickers, segmented controls, tabs and buttons all consume the same token, so one class aligns a whole row. Density still applies on top.
Form spacing tokens — override --smart-form-gap (row spacing in form.smart-stack, card bodies, and dialogs) and --smart-field-gap (label-to-control spacing) without touching markup.
.smart-reveal — fade-slide in on first scroll into view; stagger with --smart-reveal-delay. Content stays visible if JS never runs.
.smart-animate plus an effect class — opt-in .smart-enter-fade, --up, --down, --start, --end, or .smart-enter-scale entrances; matching .smart-leave-* exits; and one-shot .smart-attention-pulse, --shake, or --flash cues. Tune a single element with --smart-animation-duration, --smart-animation-delay, --smart-animation-ease, and --smart-animation-iterations. Start/end mirror in RTL and all effects stop under reduced motion.
Typography
Semantic scale: h1 through h6 use the token scale automatically; h2 is the display/section size, while h5 and h6 cover supporting and eyebrow headings.
.smart-truncate (one line), .smart-line-clamp-2/3/4 (multi-line), .smart-balance, .smart-mono, and font-weight helpers.
.smart-kbd styles shortcut hints such as ⌘ K.
Visibility
Prefer the native hidden attribute — the reset guards it against display overrides. SmartWebUI.hide(el) / SmartWebUI.show(el) toggle it, and agent nodes accept a universal hidden: true property.
.smart-hidden (display: none) when a class toggle is easier; .smart-invisible hides without removing layout
.smart-hidden-mobile hides under 50rem; .smart-visible-mobile shows only under 50rem
.smart-scroll-y / .smart-scroll-x — self-scrolling regions with thin scrollbars and contained overscroll, for message lists and long feeds.
.smart-pane-fill, .smart-pane-tall (min(60vh, 32rem)), .smart-pane-screen (100svh minus --smart-pane-offset) — pane heights for messenger-style layouts where a header or composer stays fixed.
Application layout helpers
Optional classes for common product shells — page main columns, auth forms, reading-width content, card grids, and log output. They compose with .smart-stack, .smart-cluster, and .smart-grid.
Class
Purpose
smart-page-main
Default public page main spacing
smart-shell-main
App shell main column spacing
smart-cluster--center
Horizontally center a flex cluster
smart-stack--tight
Reduced vertical stack gap
smart-auth-layout
Narrow centered auth form column (max 44rem)
smart-auth-logo
Login/register logo sizing
smart-reading-card
Prose-width card container
smart-tile-card
Icon + title link tile (with smart-card--interactive)
smart-card__feature-icon
Large icon badge for tiles and pickers
smart-grid--cards
Equal-height card grid
smart-grid--tiles
Tile grid min width (combine with --cards)
smart-grid--pickers
Choice/picker card grid
smart-card--picker
Centered picker tile styling
smart-log-panel
Scrollable monospace log output
Print
.smart-no-print hides any element on paper; popovers, toasts, dialogs, and app-shell controls are hidden automatically in @media print.
.smart-print-document flattens a card into a print-ready document — shadows removed, black on white — for invoices, quotes, and receipts.
JavaScript API
The optional script exposes a frozen SmartWebUI global. Every method works on ordinary DOM elements, so it composes with any server-rendered or client-rendered page.
One global, two validation roles.SmartWebUI.validate(form, rules) validates form fields (core). SmartWebUI.validateSurface(surface) validates agent JSON (requires smartwebui-agent.js). Do not pass surface declarations to validate(). With the agent script loaded, the same SmartWebUI object extends the core API — one script tag pair for simplicity.
SmartWebUI.update(target, content, options)
Replaces the content of an element with a View Transition when the browser supports one, or an immediate accessible update otherwise. Strings are inserted as plain text by default. Pass { html: true } only for trusted application markup, and { replace: true, html: true } to replace the element itself. Pass a Node to insert structured DOM without parsing HTML.
Agent-produced content must go through render() and patch() — not HTML strings in update().
Shows a dismissible notification in the polite live region. tone is one of success, info, warning, or danger; duration: 0 keeps it until dismissed. placement accepts top-start, top-center, top-end, bottom-start, bottom-center, or bottom-end.
Apply light/dark/auto themes, comfortable/compact density, or the solid/liquid/minimal material. Choices persist to localStorage when available and dispatch a matching smart: event.
SmartWebUI.setBusy(button, busy)
Sets aria-busy on a button and disables it while a save or other in-flight action runs. Call setBusy(button, false) to restore the previous disabled state.
SmartWebUI.validate(form, rules, options)
Runs declarative rules against a form and wires the results into the Field pattern: aria-invalid on failing controls, linked .smart-error messages, .smart-field--invalid on wrappers, and an optional FormErrors summary ({ summary: "#form-errors" }). The summary is built with DOM text nodes — labels and messages are never interpolated into HTML. Rules per field name: required, email, minLength, maxLength, pattern, match, min, max, custom(value, form), plus label and message overrides. Returns and dispatches { valid, issues } via smart:validate.
SmartWebUI.setLocale(strings)
Overrides component chrome strings — placeholders, aria labels, picker buttons, upload and validation messages — for any subset of keys (SmartWebUI.t(key) reads one back). Dates and currency always format through Intl; RTL works via dir="rtl" as always. Dispatches smart:locale.
SmartWebUI.upload(input, url, options)
Uploads the file in a dropzone-enabled file input with a live progress bar, returning a promise for the server response. Options: method, fieldName, fields (extra form values), headers. Progress and completion arrive as smart:upload-progress, smart:upload-done, and smart:upload-error events on the input.
SmartWebUI.countdown(target, seconds, options)
Renders an m:ss countdown into any element, ticking once per second, and returns a controller with stop(), start(), and reset(seconds). Options: format, warnBelow (adds .smart-countdown--warn), onTick, onExpire. Declaratively, data-smart-countdown="180" (with optional data-countdown-warn) starts on hydration — the session-timeout pattern. Events: smart:countdown, smart:countdown-expire.
copy() · confirm() · formatters
copy(text) writes plain text to the clipboard and returns it. confirm(options) opens an accessible native dialog and resolves to a boolean. formatDate(), formatNumber(), formatCurrency(), and formatRelativeTime() provide dependency-free Intl-based display formatting with optional locale settings.
debounce() · throttle() · shortcuts
debounce(callback, delay) and throttle(callback, interval) handle search and scroll work. SmartWebUI.shortcuts.register("mod+k", handler, options) registers a normalized keyboard shortcut and returns an unregister function; mod maps to Command on macOS and Control elsewhere.
observeBreakpoint(query, callback) exposes a cleanup-friendly matchMedia observer. observeLoadMore(sentinel, callback, options) wraps IntersectionObserver for infinite lists. observeConnectivity(callback) reports navigator.onLine immediately and on browser online/offline events. Each returns a cleanup function.
focusFirst() · trapFocus()
focusFirst(target, options) moves focus to the first usable descendant. trapFocus(target, options) exposes the library's focus-loop behavior for custom host surfaces and returns a cleanup function that can restore prior focus. Native dialogs remain preferred when modal semantics apply.
trackDirty() · queryState
trackDirty(form, options) compares live form data with a resettable baseline, toggles data-smart-dirty, dispatches smart:dirty, and optionally guards beforeunload. queryState.read/write/apply/bind synchronizes named filter and table controls with URLSearchParams through replace-state by default.
virtualize() · scrollToTop()
virtualize(target, items, renderItem, options) windows fixed-height rows with configurable itemHeight and overscan, returning update, refresh, scroll, and destroy controls. scrollToTop() honors reduced motion; data-smart-scroll-top turns a .smart-scroll-top button into an automatically revealed affordance.
SmartWebUI.hydrate(root)
Initializes popovers, custom selects, comboboxes, multi-selects, date and time pickers, dual ranges, ratings, masks, color outputs, command palettes, app headers, attachment removal, table selection and expandable rows, app shells, steppers, search, file/dropzone, quantity, password strength, OTP, countdowns, tabs, segmented controls, ranges, tooltips, and charts inside any element. Call it after inserting smartwebUI markup dynamically so new components behave like static ones.
TypeScript types for the core and agent globals live in smartwebui.d.ts.
Markup behaviors
Common interactions need no JavaScript of your own — add a data attribute.
data-smart-open="#dialog-id" opens that <dialog> modally and returns focus on close.
data-smart-close closes the closest dialog from any button inside it.
data-smart-collapse="#region-id" toggles the hidden attribute on any region from a remote trigger, with aria-expanded / aria-controls managed for you.
data-smart-scrollspy on a table-of-contents nav highlights the link whose section is in view via aria-current="location" — this page's sidebar uses it.
data-smart-toast with optional data-toast-title, data-toast-message, and data-toast-placement fires a toast on click.
data-smart-breadcrumbs-collapse folds deep breadcrumb middles; data-smart-scroll-top provides an automatically revealed return-to-top button; data-smart-connectivity reflects browser online/offline state.
data-smart-theme, data-smart-density, and data-smart-material apply preferences on click.
Events
Components announce changes through bubbling custom events, so integration stays decoupled from markup.
smart:tab from tab activation, smart:select from the custom select, smart:combobox from filterable fields.
smart:date and smart:time from custom date and time pickers; range pickers include start and end.
smart:tags from tag fields, smart:multiselect from multi-select dropdowns, smart:range from dual ranges, and smart:rating from ratings.
smart:attachment-remove from removable file rows; smart:copy after a successful copy action.
smart:sort from table sort buttons, smart:table-select and smart:table-action from bulk selection, smart:step from steppers, smart:chip-remove from removable chips.
smart:confirm after a confirm dialog is accepted, smart:toast-action from toast action buttons, smart:accordion from disclosure toggles, and smart:breadcrumbs when a collapsed path expands.
smart:connectivity, smart:dirty, smart:query-state, and smart:virtualize expose host-level state changes.
smart:update after update() replaces a region.
smart:quantity from stepper buttons, smart:strength while typing scored passwords, smart:otp from OTP digit rows ({ value, complete, length }), smart:validate after validate().
smart:file when a pick or drop is accepted or rejected; smart:upload-progress, smart:upload-done, smart:upload-error around upload().
smart:reorder from sortable-list drops ({ itemId, orderedIds, fromIndex, toIndex }); smart:board and smart:move from Kanban card drops ({ cardId, fromColumnId, toColumnId, fromIndex, toIndex }); smart:send from conversation composers ({ value, textarea }); RichText fields also emit smart:change with { value, control } (agent-bound controls use the surface smart:change shape instead).
smart:locale after setLocale() overrides chrome strings.
smart:theme, smart:density, smart:material when preferences change.
smart:action and smart:change from agent-rendered controls (below).
smart:surface and smart:patch after agent rendering and patching; smart:adopt after server-rendered markup is registered; smart:agent-ready when the agent runtime loads.
smart:compat with the missing feature list when data-smart-compat detects an unsupported browser; smart:stripe-ready and smart:payment-ready from the payment companion.
Agent surfaces
The optional agent runtime (smartwebui-agent.js, loaded after smartwebui.js) lets generative systems compose interfaces from a declarative JSON contract. Agents can also write hand-authored smart-* HTML directly — surfaces are the fail-closed path when JSON is the wire format.
The renderer builds elements through the DOM API and never accepts HTML strings, JavaScript, classes, or inline styles inside a surface declaration. Each node is validated against its catalog property map — unknown keys fail closed. href and src accept only http(s), mailto:, relative paths, and in-page hashes. Surface data is otherwise structurally validated: plain objects only, unique IDs, and depth, node-count, and text-length limits. Buttons emit smart:action events; the runtime never executes agent-provided code.
Stable IDs support live updates with four patch operations — data.patch, node.upsert, node.remove, and node.append — and focus is preserved across patches when possible. node.append (or SmartWebUI.append(target, { parent, node | nodes })) grows a container as items arrive, the streaming shape for SSE and WebSocket token flows.
SmartWebUI.validateSurface(surface) checks a declaration before rendering, returning { valid, errors } plus structured issues: [{ path, message }] that agents can self-correct from.
SmartWebUI.snapshot(target) reads safe live state back by stable ID: field values, selections, board order, message counts, playback position, and whether a signature is complete. Signature strokes or typed signature data are never exposed to an agent snapshot.
SmartWebUI.loadCatalog() fetches smartwebui.catalog.json, the machine-readable contract of components, properties, composition rules, and accessibility expectations.
All 50 HTML families have a declarative path through 51 nodes. RichText, Board, Conversation, Composer, Map, DataGrid, MediaPlayer, and SignaturePad expose bounded safe subsets: no rich-text HTML, credentials, query endpoints, callbacks, DRM configuration, composer prefills, signature values, or fabricated completed states.
SmartWebUI.history(target) records every patch applied to a surface with its precise inverse — undo(), redo(), clear() — so agents and users can roll back interface changes safely.
Server-side rendering:smartwebui-surface.php (a dependency-free PHP class) emits the same semantic HTML with stable IDs and an embedded declaration via SmartWebUISurface::container($surface). In the browser, SmartWebUI.adopt("#target") registers that markup without a rebuild — dispatching smart:adopt — after which patch(), snapshot(), and history() behave exactly as on client-rendered surfaces.
/llms.txt summarizes the whole library — conventions, utilities, catalog, events — in the format coding agents look for.
Dialogs and drawers accept open: true to open modally once the surface mounts; toasts are announced through the standard toast region.
Server-first workflow
The recommended path for PHP and other server stacks:
Agent or application produces a validated surface JSON object.
Server renders first paint with SmartWebUISurface::container($surface, ["id" => "report"]) — same HTML, stable data-smart-id attributes, embedded declaration.
Browser loads smartwebui.js + smartwebui-agent.js, then SmartWebUI.adopt("#report") registers the DOM without a client rebuild.
Live updates use patch(), append(), snapshot(), and history() on the adopted surface.
See the agent demo for focused product examples with live server rendering, adopt, streaming append, and undo/redo. The shipped language-neutral smartwebui.conformance.json fixtures exercise both browser and PHP renderers; repository release checks reject catalog, schema, type, or public-count drift.
Streaming & concurrency
node.append / SmartWebUI.append() is for growing lists and feeds as tokens arrive — not replacing whole trees mid-edit.
Concurrent patches to the same node are last-write-wins unless the host serializes an operation queue.
Focus is preserved across data.patch when possible; streaming append does not move focus — announce critical updates with your own live region if needed.
Use history() to roll back mistaken agent patches during development and operator workflows.
Agent security
The agent runtime validates every surface before render and refuses HTML strings in JSON, scripts, classes, and unsafe URLs. Actions are events — your application executes them; the library never runs agent code. Agent-generated markup outside the surface protocol is the same HTML API humans use — the host decides whether to trust or sanitize it.
Threat
Mitigation
XSS via agent HTML
Surfaces use typed nodes only — no HTML strings in JSON
Open redirect
href / src allowlist
Payment spoofing
Payment amounts are display-only; charge server-side
Fabricated signature or message
SignaturePad accepts no value/completed state and Composer accepts no prefill; only the user can create either value
Credential or data-source injection
Map, DataGrid, and MediaPlayer omit tokens, endpoints, callbacks, DRM, and authorization configuration
Malicious patch
Validate before render; host may reject operations
Misleading copy
Agent text is not verified — treat like user-generated content
Full threat model, CSP guidance, and reporting: SECURITY.md in the repository root.
E-commerce scope
In scope: checkout UI slot (Payment node), token-aware Stripe Elements via smartwebui-stripe.js, Address and Express Checkout element types, print styles for invoices and receipts.
Out of scope: cart logic, tax calculation, inventory, webhooks, PCI scope — the host application owns commerce rules and secrets.
“E-commerce ready” means checkout UI hooks and agent-safe payment intent — not a Shopify alternative.
Component reference
Fifty HTML families for product screens. HTML is the public API. The agent catalog provides 47 safe component types plus 4 layout primitives (51 entries, including Icon, which is not a numbered HTML family). Every family has a declarative path; integration-heavy nodes intentionally expose only bounded presentation and user-input contracts while applications retain credentials, authorization, evidence, and legal workflows. Variations stay with their parent family instead of inflating the inventory. See the inventory, the foundation showcase, and application patterns.
Initiate an immediate user action with clear hierarchy and tactile feedback.
Classes
.smart-button, modifiers --primary, --quiet, --link, --danger, --small, --large, --icon, --full; group with .smart-button-group; attach a menu with .smart-split-button
Data attributes
data-smart-toast, data-toast-title, data-toast-message on triggers; use aria-pressed for toggle groups; aria-busy="true" for a saving spinner
Events
Native click; optional toast via data-smart-toast; agent buttons emit smart:action
Agent catalog
Button — label, variant (including link), size, fullWidth, pressed, action, disabled, busy; add splitItems[] and menuLabel for the attached-menu variation
Accessibility
Visible label or aria-label on icon buttons; one primary action per decision area
data-smart-select, data-value on root and options; data-smart-anchor on popover; data-smart-password + data-smart-reveal; data-smart-copy; data-smart-strength creates a password meter; data-smart-counter pairs a textarea with its native maxlength. Use data-smart-format="number|currency|phone" with optional data-locale and required data-currency for currency.
Events
smart:select{ value, option }; smart:combobox; smart:multiselect; smart:range; smart:rating; smart:copy; smart:otp; smart:quantity; smart:strength; smart:file; smart:format{ format, value, input, hidden }; native input / change on hidden input; range updates --smart-range-fill
Agent catalog
Field uses one control family: "input", "textarea", "select", "combobox", "search", "file", "range", "date", "time", "tags", "daterange", "otp", "quantity", "multiselect", "numericrange", "rating", or "color". Optional mask is a property on text inputs, not a control type; use format: "number" | "currency" | "phone", plus locale and currency, for formatted inputs. Inputs accept text prefix/suffix or catalog-backed prefixIcon/suffixIcon; textarea counters use maxLength + counter.
Accessibility
Programmatic label; custom select exposes combobox + listbox semantics; link errors with aria-describedby
Client-side states come from native constraint validation: :user-invalid / :user-valid style touched controls (danger border, success border), required fields get an automatic * on the label, and .smart-error--live reveals its message only while the field is invalid. Server-side errors stay class-driven: .smart-field--invalid plus a visible .smart-error — what the agent emits for Field.error.
Keep default badges short. For user-generated or translated labels, use --truncate with a full title or aria-label, or --wrap when the application can give the label more vertical space. Set --smart-label-max-inline-size to tune the default 18rem limit.
Switch between peer content views without leaving the current context.
Classes
.smart-tabs, .smart-tab-list, .smart-tab, .smart-tab-panel; vertical: .smart-tabs--vertical + aria-orientation="vertical" — side list for settings layouts, Up/Down keys move between tabs, collapses to horizontal under 50rem
Events
smart:tab{ tab }; arrow, Home, and End keyboard navigation
Agent catalog
Tabs — label, selected, items[] with value, label, content
Accessibility
Full ARIA tablist / tab / tabpanel wiring with aria-controls and aria-selected
data-smart-table on the wrap; data-smart-sort="columnKey" on sort buttons; data-smart-selected on <tr>; data-smart-table-all on select-all; data-smart-table-action on bulk actions
Advanced operational datasets with application-owned server queries, editable cells, grouping, column layout, selection, and CSV export.
Assets
Load smartwebui-datagrid.js after smartwebui.js. The companion is optional and does not change the basic Table family.
Root
.smart-data-grid[data-smart-data-grid]; initialize page state with data-grid-page, data-grid-page-size, and data-grid-total. Add data-grid-storage-key only when a user-specific column layout may be stored locally.
Queries
Sort, filters, page size, and previous/next dispatch cancelable smart:grid-query with { reason, state, complete, fail }. Call preventDefault(), authorize and fetch on the server, replace the rendered rows, then call complete({ total, page, pageSize }).
Columns
data-grid-column gives every header/cell a stable key. Use data-grid-sort, data-grid-pin, data-grid-resize, data-grid-column-move, and persistent toolbar controls with data-grid-visibility="key". Column changes emit smart:grid-column.
Edit and export
data-grid-editable cells dispatch cancelable smart:grid-edit with accept()/reject(). data-grid-export creates a current-view CSV by default; prevent smart:grid-export when the server must export the full filtered dataset.
Agent catalog
DataGrid — required label and columns[]; optional bounded rows[], loading/empty/error state, pagination, selection, sorting, and compact presentation. Endpoints, callbacks, authorization, persistence keys, and export commands are rejected.
Accessibility
Keep native table markup and a caption. Reordering supports Alt+Arrow on the labelled handle; resizing supports Arrow keys on the separator; Enter/F2 edits; grouped rows use labelled expansion buttons. Server authorization and validation remain application responsibilities.
Server query contract
<script defer src="/assets/smartwebui-datagrid.js"></script>
<section class="smart-data-grid" data-smart-data-grid
data-grid-page="1" data-grid-page-size="25" data-grid-total="840">
<!-- toolbar, native table, and footer -->
</section>
<script>
grid.addEventListener("smart:grid-query", async event => {
event.preventDefault();
try {
const result = await fetchGrid(event.detail.state);
renderRows(result.rows);
event.detail.complete({ total: result.total });
} catch (error) {
event.detail.fail("Accounts could not be loaded.");
}
});
</script>
Accessible file picker with live filename feedback.
Classes
.smart-file, .smart-file__control, .smart-file__label, .smart-file__name; post-upload display uses the List-family .smart-attachment-list and .smart-attachment
Data attributes
data-placeholder on .smart-file__name; data-smart-dropzone on .smart-file enables drag-and-drop; data-max-size (bytes) and accept validate picks with inline .smart-file__error feedback
Events
Native change on file input; smart:file on accept/reject; SmartWebUI.upload(input, url, { method, fieldName, fields, headers }) uploads with a progress bar and smart:upload-progress / -done / -error events
Agent catalog
Field with control: "file", accept, buttonLabel, dropzone: true
Use the toolbar modifier for filters, search, view controls, and a page-level action. The toolbar remains in one compact row from tablet widths upward and wraps naturally on smaller screens.
data-smart-shell; data-collapsed for the icon rail; data-nav-open for the mobile drawer; data-smart-shell-menu, data-smart-shell-collapse, data-smart-shell-close
Agent catalog
AppShell — brand, recursive items[] groups with open; leaf items accept icon; collapsed activates the icon rail; accepts child content nodes
Accessibility
Sidebar uses nav; current page link has aria-current="page"; menu and collapse expose aria-expanded
Use --truncate plus a full title or aria-label for user-created filter text; use --wrap only where a taller chip is acceptable. Both variants use --smart-label-max-inline-size (18rem by default).
data-smart-shell hydrates an AppShell; AppHeader reads aria-current="page" on the active link. Mobile collapse is automatic below the configured breakpoint.
Events
smart:change on navigation interaction; AppShell retains its own smart:shell lifecycle. No dedicated header/footer event — navigation is link-based.
Agent catalog
AppHeader — required brand + items[]; optional brandHref, navigationLabel, actions[], sticky. Footer — optional text, links[], label. See smartwebui.catalog.json for the validated property map.
Accessibility
The header is a <header> landmark with a labelled <nav>; the footer is a <footer> landmark. Active links carry aria-current="page". Mobile collapse preserves the navigation label and focus order.
data-smart-command on the <dialog>; data-smart-command-shortcut (for example mod+k); data-smart-command-search on the filter input; data-smart-command-item with role="option" on each action; optional data-smart-command-group for labeled sections.
Events
smart:action{ action, id } when an item is chosen; the dialog uses native close. Arrow keys move between results, Enter activates, Escape closes.
Agent catalog
CommandPalette — required label + items[] (label, action, optional group, shortcut); optional placeholder, open, shortcut. See smartwebui.catalog.json for the validated property map.
Accessibility
The palette is a native <dialog> with role="dialog". The listbox uses role="listbox" with role="option" items. Active selection follows aria-activedescendant. The search input is auto-focused on open; focus returns to the trigger on close.
One family of token-drawn SVG marks for product analytics and operations: sparkline, bar, stacked bar, line, area, combo, scatter, donut (with an optional hole whose zero value renders a filled pie), and gauge.
Classes
.smart-chart with --sparkline, --bar, --stacked-bar, --line, --area, --combo, --scatter, --donut, or --gauge; plus .smart-chart__plot, .smart-chart__caption, and .smart-chart__legend
Data attributes
data-smart-chart, data-mark, optional data-hole (donut, 0–0.85), optional data-values + data-labels, or a JSON payload. Hydration exposes series count, axis names, and an explicit summary through stable data-chart-* metadata. Series tones are token names only.
Events
smart:chart-select{ index, x, values, summary } from click or arrow keys; hover and keyboard focus show a value tooltip in the same language as .smart-tooltip
Agent catalog
Chart — required label; optional axes, units, summary, and series[]. Combo series choose mark and axis; scatter uses numeric x/y points; donut accepts a numeric hole (0–0.85; 0 renders a filled pie without center labels); gauge accepts min, max, target, and ordered thresholds. At most 8 series and 48 finite points. No SVG, hex, or path data from JSON.
Accessibility
Figure + caption, decorative SVG, explicit trend summary, machine-readable axis metadata, and a visually hidden data table with units. Gauge represents an operational range; Progress ring remains the completion indicator.
data-smart-payment on the container; the mount slot id is derived from the node id
Events
smart:payment-ready when the host-mounted element finishes loading; aria-busy on the slot while it loads
Agent catalog
Payment — label, amount + currency (display only), description. Never keys, secrets, or card data.
Stripe
Load the optional smartwebui-stripe.js companion and call SmartWebUIStripe.mount(slot, { publishableKey, clientSecret }). Stripe.js lazy-loads from js.stripe.com, and the Elements appearance is derived from your --smart-* tokens — re-synced automatically on theme, density, and material changes.
Markup
<!-- What an agent surface renders for { type: "Payment", id: "checkout", label: "Pro plan", amount: 24, currency: "USD" } -->
<div class="smart-payment" data-smart-payment>
<div class="smart-payment__summary">
<span class="smart-payment__label">Pro plan</span>
<span class="smart-payment__amount">$24.00</span>
</div>
<!-- The mount slot id is derived from the node id (here "checkout-element") -->
<div class="smart-payment__element" id="checkout-element"></div>
</div>
<script type="module">
// Host code — keys and clientSecret never appear in agent JSON.
// Select the renderer-derived slot id; do not hardcode a different selector.
await SmartWebUIStripe.mount("#checkout-element", {
publishableKey: "pk_live_…",
clientSecret: paymentIntentClientSecretFromYourServer,
});
// Address and Express Checkout (Apple Pay / Google Pay) mount the same way:
await SmartWebUIStripe.mount("#address-element", {
publishableKey, clientSecret,
elementType: "address",
addressMode: "shipping",
});
await SmartWebUIStripe.mount("#express-element", {
publishableKey, clientSecret,
elementType: "expressCheckout",
});
</script>
38 Carousel & lightbox
Momentum media browsing: a snap-scrolling slide strip, a gallery grid, and a fullscreen zoomable viewer — Apple-style page dots included.
data-smart-carousel on the section with optional data-loop, data-autoplay, data-interval; data-smart-carousel-track, -prev, -next, -dot, -toggle, -live; lightbox data-smart-lightbox, -open, -stage, -image, -counter, -caption, -zoom, -prev, -next; slides and triggers carry data-index
Events
smart:slide{ index } when the active slide changes — swipe, dots, arrows, keyboard, autoplay, or viewer navigation. The viewer itself is a native <dialog> (native close)
Agent catalog
Carousel — required label + items[] (src, alt, caption, optional nested content nodes); variant (carousel, gallery), ratio (1x1, 4x3, 16x9, 21x9), selected, autoplay, interval, loop, lightbox. At most 24 items; image URLs follow the surface src policy.
Accessibility
aria-roledescription="carousel" with slides announcing “N of M”; Arrow, Home and End keys on the track; iOS-style dots are labelled buttons with aria-current; slide changes are announced politely; the viewer is a native modal dialog with visible close, labelled zoom toggle, and zoom reset on navigation. Autoplay pauses on hover, focus, and offscreen — and never starts under prefers-reduced-motion.
data-smart-richtext; data-smart-richtext-sync on its type="hidden" input; data-smart-richtext-required, optional data-smart-richtext-required-message, and optional data-smart-richtext-allow (a subset of p, br, strong, b, em, i, u, ul, ol, li, a)
Events
smart:change with { value, control }; the hidden input also emits native input and change
Agent catalog
RichText — required label; optional plain-text value, placeholder, fixed-command toolbar[], required state, and disabled state. HTML, markup, arbitrary commands, and allowlists are rejected.
Accessibility
The visible contenteditable editor must use aria-labelledby or aria-label. Required validation stays on the visible editor, focuses it on error, and stateful toolbar controls expose aria-pressed.
data-smart-board on the board; data-column-id / optional data-column-label on columns; data-card-id / optional data-card-label on cards; the library creates data-smart-board-live when no live region is supplied
Events
smart:board and compatibility smart:move with card ID, source/target column IDs, and indexes
Agent catalog
Board — required label and bounded columns[]; columns accept IDs, labels, and plain-text cards. Agents can describe the view, while the host authorizes and persists movement events.
Accessibility
Focusable cards lift with Enter or Space; arrows preview a move (horizontally mirrored in RTL); Enter or Space drops; Escape cancels. A polite live region announces lift, move, drop, cancellation, and boundaries. Announce the server-persisted outcome or rollback in the host application.
Height
The default minimum is --smart-board-min-block-size: 18rem. Use .smart-board--compact or override that token for small boards without shrinking task cards.
data-smart-conversation and data-smart-composer; message alignment uses data-own="true|false"
Events
smart:send from the composer with { value, composer }
Agent catalog
Conversation presents bounded plain-text messages[] and may include a safe composer configuration. Composer provides standalone user-authored input. Agents cannot prefill or send composer content; the host owns delivery.
Accessibility
Use a labelled role="log" message list with an appropriate live-region policy. The optional header takes only its content height; messages consume the remaining space. Without a header, the messages area fills the component.
data-smart-mapkit; data-smart-map-canvas; center and span via data-latitude, data-longitude, data-latitude-delta, data-longitude-delta; optional data-map-type="standard|mutedStandard|satellite|hybrid"; locations use data-smart-map-location plus coordinates, title, subtitle, color, and glyph
JavaScript
Load smartwebui-mapkit.js, call SmartWebUIMapKit.configure({ tokenEndpoint: "/api/map-token" }), then SmartWebUIMapKit.init(). A direct domain-restricted token or custom authorizationCallback is also supported.
Events
smart:map-ready with the map and annotations; smart:map-error with the error; document-level smart:mapkit-ready when the companion API is available
Agent catalog
Map — required label; optional bounded viewport, locations[], map type, compact presentation, and loading/error state. Providers, tokens, credentials, callbacks, and scripts are rejected.
Accessibility
Give the figure an accessible label, retain the visible semantic locations for keyboard and non-map users, and provide ordinary Apple Maps links for directions. The map canvas supplements rather than replaces address content.
Security
No credential is bundled or accepted through HTML data attributes. Restrict Maps tokens to production domains and serve refreshable tokens from a same-origin endpoint when appropriate.
Live shell example · MapKit tiles require the host application's Apple Maps token.
44 Media player
Progressive video, audio, and playlist playback with a shared accessible control contract and native fallback.
Assets
Load smartwebui-media.js after smartwebui.js. Without the companion, the native controls attribute remains available.
Classes
.smart-media; variants --video, --audio, --playlist; add --controls-docked when Audio or Playlist controls are a direct final child and should span the complete player width. Core parts __stage, __element, __meta, __controls, __button, __seek, __volume, __playlist, and __track; optional presentation parts __badge, __eyebrow, __artwork, __playlist-art, and primary play control __button--primary
Use stable data-media-track IDs with data-src, data-type, data-title, data-artist, and optional data-artwork. data-media-autoplay-next advances after a track ends.
Events
smart:media-ready, smart:media-state, smart:media-error, and cancelable smart:media-track. Prevent the track event to resolve an authorized URL, then call event.detail.load(url).
Agent catalog
MediaPlayer — required label; optional video, audio, or playlist metadata using policy-checked URLs plus loading/playing/paused/error state. Credentials, inline media, autoplay, callbacks, and DRM configuration are rejected.
Accessibility
Keep the media element’s native fallback, provide captions or transcripts, label every icon button, and give the player an accessible name. Focused-player shortcuts are Space/K, Left/Right, M, C, F, and P.
Application boundary
The library does not bundle media, codecs, DRM, analytics, streaming adapters, or provider SDKs. Hosts own authorization, signed URLs, CORS, rights, captions, transcripts, and codec fallbacks.
Drawn and typed e-sign intent capture with responsive rendering, validation, and explicit application boundaries.
Asset
Load smartwebui-signature.js after smartwebui.js. It hydrates data-smart-signature roots and exposes SmartWebUISignature.
Modes and states
data-signature-mode="draw|type"; Empty, Signed, Disabled, and Error states are managed with data-signature-state. Mark the root data-signature-required when submission must be blocked while empty.
Output
data-signature-value receives compact JSON containing normalized strokes or typed text. Optional data-signature-image receives a PNG data URL. Drawn output intentionally excludes pressure, speed, and timestamps.
API and events
hydrate, get, clear, undo, and exportImage; events smart:signature-ready, smart:signature-change, smart:signature-clear, and smart:signature-invalid.
Agent catalog
SignaturePad — required label; optional description, mode, required/error copy, hint, disabled state, and empty/loading/error state. Agent declarations cannot contain a signature, strokes, typed name, image, completed state, or submission action.
Accessibility
Provide the typed mode as a keyboard equivalent, label the canvas and controls, keep visible consent copy, and place validation text in data-signature-error. Command/Control+Z undoes the last drawn stroke.
Application boundary
This component captures intent only. The host owns disclosure and consent, signer authentication, document hash/version, server validation, audit evidence, encryption, retention/deletion, and jurisdiction-specific legal review. A canvas mark alone does not establish identity or enforceability.
A two-pane workspace with pointer and keyboard resizing plus an optional responsive stack.
Classes
.smart-split-pane, .smart-split-pane__pane, and .smart-split-pane__separator.
Data attributes
Set data-smart-split-pane, optional data-split-direction="horizontal|vertical", and data-split-collapse-at. The separator requires data-smart-splitter.
Events
smart:split-resize{ value, direction }, where value is the first pane’s percentage.
Agent catalog
SplitPane — optional direction, value (20–80), and collapseAt. Its first child renders in the first pane; remaining children render in the second.
Accessibility
The separator is a labelled ARIA separator. Arrow keys resize by 2%, Shift+Arrow by 10%, and Home/End select bounds.
Compose search, saved views, and removable active filters for data-heavy screens.
Classes
.smart-filter-bar, .smart-filter-bar__row, .smart-filter-bar__search, .smart-filter-bar__controls, and .smart-filter-bar__active.
Data attributes
Set data-smart-filter-bar on the section. Search uses data-smart-filter-query; active chips use data-smart-filter-chip and data-smart-filter-remove; saved views use data-smart-filter-view; clear-all uses data-smart-filter-clear. Anchor the saved-views popover with data-smart-anchor on the chevron trigger id.
Events
smart:filter-add{ query, filters, view } requests the host’s filter chooser; smart:filter-change{ query, filters, view }, smart:filter-remove{ key, label, value }, and smart:view-change{ view } keep the host in control of queries and saved views.
Agent catalog
FilterBar — optional query, views[], view, and filters[] with key, label, and value.
Accessibility
Search uses type="search" with a labelled clear control. Active filters expose removable chips with explicit remove labels.
Bell trigger with grouped inbox notifications and mark-read affordances.
Classes
.smart-notification-center, .smart-notification-center__trigger, .smart-notification-center__badge, .smart-notification-center__panel, and grouped .smart-notification-center__group* sections reusing .smart-notification-list.
Data attributes
Set data-smart-notification-center on the wrapper. The trigger uses popovertarget and optional data-smart-notification-trigger. The panel uses data-smart-notification-panel. Rows use data-smart-notification-id; header actions use data-smart-notification-mark-all; the badge uses data-smart-notification-count.
Events
smart:notification-read{ id, item } when a row is marked read. Read state and delivery remain host-owned.
Agent catalog
NotificationCenter — optional unreadCount, flat items[], or grouped groups[] with notification title, message, time, and unread.
Accessibility
The trigger exposes unread count in a badge. The panel is a labelled, non-modal dialog popover; focus moves to its first action when opened, while native popover light-dismiss returns control to the trigger.
Four composable layout nodes for agent surfaces. They also map to utility classes in hand-written HTML.
Stack
Vertical arrangement with consistent spacing. CSS: .smart-stack. Property: gap (small, medium, large). Forms use --smart-form-gap automatically when marked form.smart-stack.
Responsive peer grid. CSS: .smart-grid. Property: minimum (compact, standard, wide). Grids containing .smart-field widen column gap and default to an 18rem minimum.
Text
Trusted text with semantic emphasis. Property: text, as (p, strong, small, h2, h3), tone.
See also application layout helpers in Utilities — page shells, auth columns, card grids, and log panels built from the same stack/cluster/grid primitives.
Global behaviors
Shared data attributes and library events used across multiple components.
data-smart-counter, data-smart-connectivity, data-smart-breadcrumbs-collapse, data-smart-scroll-top — hydrate counters and application-state affordances
data-smart-anchor — popover positioning anchor ID
data-smart-tree — hydrates a role="tree"; Arrow keys expand, collapse, and traverse visible treeitems. data-smart-context-menu="menu-id" opens a native-popover menu on right-click or Shift+F10. data-smart-split-pane hydrates an adjustable layout; pair it with data-smart-splitter and optional data-split-collapse-at. data-smart-filter-bar hydrates search, saved views, and removable filter chips. data-smart-notification-center hydrates the bell inbox with mark-read updates.
Call SmartWebUI.hydrate(root) after inserting markup dynamically. Machine-readable agent contracts live in smartwebui.catalog.json.
Materials
Solid surfaces are the default. Liquid and Minimal are opt-in global materials using the same markup: set <html data-material="liquid">, data-material="minimal", or call SmartWebUI.setMaterial("liquid") / setMaterial("minimal").
Liquid — tune with the --smart-liquid-* tokens; lower --smart-liquid-opacity values create greater transparency. Dark Liquid is thinner and more specular than Light. Liquid uses three optical weights: full frost on chrome (dialogs, command, toasts, headers), thinner glass on controls, and almost-solid fills on content (cards, tables, lists, boards). Popovers use a clearer nested glass so they sit above sheets. Connected controls — split buttons, input groups, pagination, and page-header toolbars — share one optical container. Pointer tracking needs no component initialization. The effect disables itself for reduced motion, touch-only input, and accessibility preferences, and smartwebUI increases opacity when the browser requests reduced transparency or increased contrast.
Minimal — tune with the --smart-minimal-* tokens for a modern flat skin aimed at dense professional apps. Controls use transparent fills and thin borders instead of elevation; primary and status actions use accent-colored labels and borders instead of solid fills; cards, tables, and data surfaces sit flush on the canvas; dialogs and popovers keep a border-led separation without blur or glass. No pointer tracking or backdrop filters — Minimal pairs well with compact density for admin, CRM, and operations interfaces.
Browser policy
smartwebUI 1.5 sets a fixed September 2024 browser baseline: Chrome and Edge 129+, Firefox 130+, and Safari 18+. This reference covers color-mix(), cascade layers, the Popover API, @starting-style, and light-dark(). No legacy bundles or polyfills are shipped. Browsers that expose the required features may also work, but these versions define the tested support floor.
Who this is for
Teams that choose maintainability and modern platform APIs over supporting browsers older than the reference baseline. Internal tools, public SaaS on evergreen browsers, and agent-built dashboards fit well.
Who should not adopt the full stack
Environments with frozen corporate browsers or old embedded WebViews
Kiosks or devices that cannot receive security updates
Products with contractual legacy-browser SLAs — use tokens and hand-authored HTML without Popover-dependent components if you need a partial fit
What unsupported clients see
With data-smart-compat, a dismissible banner asks users to update. Core content remains readable where CSS parses; interactive components that depend on Popover or dialog may degrade. The default banner uses inline styles so it appears even when the main stylesheet cannot load.
Bidirectional layouts are supported throughout: spacing, borders, and radii use logical properties, so setting dir="rtl" mirrors the interface. A handful of physical-direction exceptions (switch knob, combobox chevron, calendar nav glyphs) are corrected with html[dir="rtl"] overrides.
Compatibility banner
Add data-smart-compat to your <html> element and smartwebUI feature-detects the baseline at boot — Popover API, <dialog>, color-mix(), light-dark(), :has(), logical properties. On a browser that misses any of them, a dismissible warning banner appears telling the end user the app deliberately uses the latest standards and asking them to update. Provide your own markup with <div class="smart-compat-banner" data-smart-compat-banner hidden> (optionally a data-smart-compat-dismiss button), or let the library inject a default — inline-styled so it survives even browsers too old for the layered stylesheet. The result also lands on <html data-smart-compat="supported|unsupported"> and a smart:compat event with the missing feature list.
Quality & accessibility
smartwebUI targets WCAG 2.2 AA at the component level. Keyboard operation, visible focus, reduced-motion support, and AA contrast in the default themes are engineering requirements, verified per release and documented in QUALITY.md and ACCESSIBILITY.md.
Complete pages still require an application-level audit: heading order, landmarks, error identification, zoom and reflow, custom themes, dir="rtl", and dynamic content. Date grids follow the locale week start. See the changelog for release history.
QUALITY.md documents contrast targets and release acceptance gates. ACCESSIBILITY.md separates component responsibilities from host-app obligations.
Agent-specific security boundaries: agent security and SECURITY.md.
The marketing site loads optional first-party analytics from analytics.elonovo.com only when the browser does not send Do Not Track or Global Privacy Control. The agent demo page does not load analytics.