foundation / 03

Installation

tokens.css + input.css
head.html
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="components/input/input.css">

Icon adornment

input / Icon adornmentinteractive
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

input / Errorinteractive
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