Installation
tokens.css + input.csshead.html
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="components/input/input.css">Icon adornment
Use a short name the agent can reference.
Code
input.html + input.css
input
<style>
.au-input {
--au-input-bg: var(--au-surface);
--au-input-border: var(--au-border-color);
--au-input-radius: var(--au-radius-lg);
--au-input-height: 40px;
appearance: none;
background: var(--au-input-bg);
border: 1px solid var(--au-input-border);
border-radius: var(--au-input-radius);
color: var(--au-fg);
font: 400 15px/1.4 var(--au-font-sans);
letter-spacing: -0.01em;
min-height: var(--au-input-height);
padding: 0 16px;
transition: border-color var(--au-duration-fast) var(--au-ease), box-shadow var(--au-duration-fast) var(--au-ease);
width: 100%;
}
.au-input::placeholder { color: var(--au-fg-subtle); }
.au-input:hover:not(:disabled) { border-color: var(--au-border-emphasis); }
.au-input:focus-visible { border-color: var(--au-border-emphasis); box-shadow: var(--au-focus-ring); outline: 2px solid var(--au-focus); outline-offset: 2px; }
.au-input:disabled { cursor: not-allowed; opacity: 0.55; }
.au-input[aria-invalid="true"],.au-input--error { border-color: var(--au-danger); }
.au-input[aria-invalid="true"]:focus-visible,.au-input--error:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--au-danger) 22%, transparent); }
.au-input--sm { --au-input-height: 36px; --au-input-radius: var(--au-radius-md); font-size: 13px; }
.au-input--lg { --au-input-height: 48px; --au-input-radius: var(--au-radius-xl); font-size: 16px; }
.au-input-field { display: grid; gap: 8px; }
.au-input-field__label { color: var(--au-fg); font-size: 13px; font-weight: 600; }
.au-input-field__hint { color: var(--au-fg-subtle); font-size: 12px; line-height: 1.4; }
.au-input-field__error { color: var(--au-danger); font-size: 12px; line-height: 1.4; }
@media (prefers-reduced-motion: reduce) {.au-input { transition-duration: 0.01ms; } }
</style>
<div class="au-input-field"><label class="au-input-field__label" for="project-name">Project name</label><input class="au-input" id="project-name" name="project-name" type="text" placeholder="release-notes"><span class="au-input-field__hint">Use a short name the agent can reference.</span></div>Error
Choose a name before continuing.
Code
input.html + input.css
input
<style>
.au-input {
--au-input-bg: var(--au-surface);
--au-input-border: var(--au-border-color);
--au-input-radius: var(--au-radius-lg);
--au-input-height: 40px;
appearance: none;
background: var(--au-input-bg);
border: 1px solid var(--au-input-border);
border-radius: var(--au-input-radius);
color: var(--au-fg);
font: 400 15px/1.4 var(--au-font-sans);
letter-spacing: -0.01em;
min-height: var(--au-input-height);
padding: 0 16px;
transition: border-color var(--au-duration-fast) var(--au-ease), box-shadow var(--au-duration-fast) var(--au-ease);
width: 100%;
}
.au-input::placeholder { color: var(--au-fg-subtle); }
.au-input:hover:not(:disabled) { border-color: var(--au-border-emphasis); }
.au-input:focus-visible { border-color: var(--au-border-emphasis); box-shadow: var(--au-focus-ring); outline: 2px solid var(--au-focus); outline-offset: 2px; }
.au-input:disabled { cursor: not-allowed; opacity: 0.55; }
.au-input[aria-invalid="true"],.au-input--error { border-color: var(--au-danger); }
.au-input[aria-invalid="true"]:focus-visible,.au-input--error:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--au-danger) 22%, transparent); }
.au-input--sm { --au-input-height: 36px; --au-input-radius: var(--au-radius-md); font-size: 13px; }
.au-input--lg { --au-input-height: 48px; --au-input-radius: var(--au-radius-xl); font-size: 16px; }
.au-input-field { display: grid; gap: 8px; }
.au-input-field__label { color: var(--au-fg); font-size: 13px; font-weight: 600; }
.au-input-field__hint { color: var(--au-fg-subtle); font-size: 12px; line-height: 1.4; }
.au-input-field__error { color: var(--au-danger); font-size: 12px; line-height: 1.4; }
@media (prefers-reduced-motion: reduce) {.au-input { transition-duration: 0.01ms; } }
</style>
<div class="au-input-field"><label class="au-input-field__label" for="project-name-error">Project name</label><input class="au-input au-input--error" id="project-name-error" name="project-name" type="text" aria-invalid="true" value=""><span class="au-input-field__error">Choose a name before continuing.</span></div>Component contract
- Install
- tokens.css · input.css
- States
- idle, hover, focus-visible, disabled, and error via aria-invalid + data-revealed
- Host
- validation, persistence, and request lifecycle
For agents
input.contract
# agent-ui / input
component: input
selector: .au-input
data_au_component: input
purpose: Text field with label, hint, error affordances, and optional icon adornment slot for host forms.
install:
- tokens.css
- input.css
states: idle, hover, focus-visible, disabled, and error via aria-invalid + data-revealed.
css_variables: --au-input-height, --au-input-radius
events: native form, focus, and click only — no custom events or runtime required
no_javascript: Native inputs submit and validate without script; error text renders without data-revealed.
host_owns: The host owns validation, persistence, and request lifecycle.
accessibility: Associate labels with inputs. Errors use role=alert and aria-describedby — never color alone.
security: Treat values as untrusted. Validate length and authorization on the host.
rules:
- Host owns execution, authorization, persistence, validation, and state transitions.
- Components render host-provided state; they never execute tools or imply approval.
- Escape untrusted model output, tool args, and tool output before insertion.
- Use only documented data-au-* attributes and data-au-state values.
- Keep the no-JS path usable. Do not add React, Tailwind, bundlers, or remote assets.
source: components/input/input.{html,css} + README.md + fixture.html