Forms

Text inputs, select, textarea, checkboxes, radios, validation states, and helper text.

ASW styles all standard form elements via element selectors — no wrapper classes needed. Labels are block-level by default. Fields expand to full container width. Validation state is communicated through aria-invalid, keeping semantic meaning intact and observable by assistive technology.


Text input

A <label> wrapping an <input> is the simplest form pattern. The label is correctly associated by containment — no for/id pair needed, though both approaches work.

<label>Email address
  <input type="email" name="email" placeholder="you@example.com">
</label>

Live demo

Inputs are 100% wide by default. To constrain width, wrap the label in a container with a width or grid column.


Textarea

A multi-line input. ASW sets resize: vertical so users can adjust height but not accidentally break horizontal layout.

<label>Message
  <textarea name="message" rows="4" placeholder="Your message…"></textarea>
</label>

Live demo


Select

A dropdown select. The chevron indicator is a CSS background image injected by --asw-icon-chevron — no icon font or SVG needed. Multi-select ([multiple]) drops the chevron and applies accent colour to selected options.

<label>Country
  <select name="country">
    <option value="">Select…</option>
    <option value="de">Germany</option>
    <option value="fr">France</option>
    <option value="it">Italy</option>
  </select>
</label>

Live demo

Hold Ctrl (Windows/Linux) or ⌘ (macOS) to select multiple options.

Checkboxes and radios

ASW uses accent-color to theme native checkboxes and radio buttons to the framework's accent colour. They remain native controls — no custom SVG replacements.

There are two placement patterns: inline label wrapping, and sibling label. Both work correctly with ASW.

Wrapping label (recommended)

<label>
  <input type="checkbox" name="agree">
  I agree to the terms
</label>

Live demo — checkboxes

Live demo — radios

Preferred contact method

Sibling pattern

Alternatively, place the checkbox/radio before the label as a sibling. The for/id association is required in this pattern.

<input type="checkbox" id="agree" name="agree">
<label for="agree">I agree to the terms</label>

Fieldset and legend

<fieldset> groups related fields under a <legend> header. ASW strips the fieldset border and resets padding — the visual grouping comes from layout and the legend label, not a box.

<fieldset>
  <legend>Billing address</legend>
  <label>Street <input type="text" name="street"></label>
  <label>City <input type="text" name="city"></label>
  <label>Postcode <input type="text" name="postcode"></label>
</fieldset>

Live demo

Billing address

Helper text

Place a <small> element immediately after an <input>, <select>, <textarea>, or <fieldset> to render muted descriptive text. The margin is negative to close the gap left by the field's bottom margin.

<label>Username
  <input type="text" name="username">
</label>
<small>3–20 characters, letters and numbers only.</small>

Live demo

3–20 characters, letters and numbers only. Read-only. Contact your administrator to rotate this key.

Validation states

Set aria-invalid="true" on an invalid field and aria-invalid="false" on a valid one. ASW applies red border for invalid and accent border for valid. Helper text inherits the corresponding colour automatically.

<!-- Invalid -->
<label>Email
  <input type="email" aria-invalid="true" value="not-an-email">
</label>
<small>Enter a valid email address.</small>

<!-- Valid -->
<label>Username
  <input type="text" aria-invalid="false" value="vigilio">
</label>
<small>Username is available.</small>

Live demo

Enter a valid email address. Username is available. Message must be at least 20 characters.

Use aria-describedby to associate the helper text element with the input when they are not adjacent siblings, or when you need to be explicit for assistive technology.


Disabled fields

Apply disabled to prevent interaction. Opacity drops to --asw-disabled-opacity. Disabled fields are excluded from form submission.

<label>Account type
  <input type="text" disabled value="Free tier">
</label>

Live demo

Upgrade to change this.

Complete form example

A full login form demonstrating the patterns above in combination.

<form method="post" action="/login">
  <fieldset>
    <legend>Sign in</legend>
    <label>Email
      <input type="email" name="email" autocomplete="email" required>
    </label>
    <label>Password
      <input type="password" name="password" autocomplete="current-password" required>
    </label>
    <label>
      <input type="checkbox" name="remember">
      Remember me
    </label>
  </fieldset>
  <button type="submit">Sign in</button>
  <a href="/forgot-password">Forgot password?</a>
</form>

Live demo

Sign in

Forgot password?


Design tokens

Token Controls
--asw-input-bg Field background colour (default: secondary bg)
--asw-input-border Field border colour (resting state)
--asw-input-active-bg Field background on focus/active
--asw-input-padding-y Vertical padding inside fields
--asw-input-padding-x Horizontal padding inside fields
--asw-input-selected Selected option background in multi-select
--asw-error Border colour for aria-invalid="true"
--asw-disabled-opacity Opacity for disabled form controls

Accessibility

  • Every input must have an associated label. Use the wrapping pattern (<label><input></label>) or the for/id pair. Placeholder text is not a label.
  • aria-invalid is the correct mechanism for communicating validation state to assistive technology. Don't rely on border colour alone.
  • Group related radio buttons and checkboxes in a <fieldset> with a <legend>. Screen readers announce the legend before each control in the group.
  • Use autocomplete attributes on login and payment forms. It aids users with memory or motor impairments and is required for WCAG 1.3.5 (AA).
  • Required fields: use the required attribute — it prevents native form submission without a value and exposes the requirement to assistive technology. Don't rely solely on a visual asterisk.