Skip to content

Input

Text inputs for single-line text entry. Supports all standard HTML input types.

Inputs are width: 100% by default. Do not add af-w-full. Stretch buttons with that utility instead. af-is-autosize is the exception (width: fit-content).

Every input must have an associated <label> — for matching the input id, or wrap the control. A placeholder is not a label. Use the Field pattern for the usual label + control + help/error structure.

<div class="af-stack">
  <div class="af-field">
    <label class="af-field__label" for="input-text">Name</label>
    <input type="text" id="input-text" class="af-input" placeholder="Ada Lovelace" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-email">Email</label>
    <input type="email" id="input-email" class="af-input" placeholder="ada@example.com" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-password">Password</label>
    <input type="password" id="input-password" class="af-input" placeholder="••••••••" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-search">Search</label>
    <input type="search" id="input-search" class="af-input" placeholder="Find packages" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-tel">Phone</label>
    <input type="tel" id="input-tel" class="af-input" placeholder="+61 4 0000 0000" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-url">Website</label>
    <input type="url" id="input-url" class="af-input" placeholder="https://example.com" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-number">Quantity</label>
    <input type="number" id="input-number" class="af-input" placeholder="12" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-date">Date</label>
    <input type="date" id="input-date" class="af-input" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-time">Time</label>
    <input type="time" id="input-time" class="af-input" />
  </div>
</div>
Please enter a valid email address
<div class="af-stack">
  <div class="af-field">
    <label class="af-field__label" for="input-normal">Name</label>
    <input type="text" id="input-normal" class="af-input" placeholder="Ada Lovelace" />
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-error">Email</label>
    <input
    type="email"
    id="input-error"
    class="af-input af-is-error"
    aria-invalid="true"
    aria-describedby="input-error-message"
    placeholder="ada@example.com"
  />
    <div class="af-field__error" id="input-error-message">Please enter a valid email address</div>
  </div>
  <div class="af-field">
    <label class="af-field__label" for="input-disabled">Name</label>
    <input type="text" id="input-disabled" class="af-input" disabled placeholder="Ada Lovelace" />
  </div>
</div>

Use af-is-autosize to let single-line inputs grow with content:

<div class="af-field">
  <label class="af-field__label" for="input-autosize">Tag</label>
  <input type="text" id="input-autosize" class="af-input af-is-autosize" placeholder="Type to grow" />
</div>

Info: Inputs growing horizontally as you type can cause layout shifts (bad in modern UI/UX). Use autosize only for narrow, controlled cases (like tag inputs or inline search).

Form controls use shared control tokens plus input-specific tokens (applies to inputs, selects, and textareas):

  • --af-control-radius, --af-control-border, --af-control-border-width
  • --af-input-radius (defaults to --af-control-radius)
  • --af-input-min-height, --af-input-border-width (defaults to --af-control-border-width), --af-input-border
  • --af-input-border-hover, --af-input-border-focus
  • --af-input-font-size, --af-input-leading, --af-input-placeholder-color
  • --af-input-padding-x, --af-input-padding-y
<style>
  :root {
    --af-input-min-height: 3rem;
    --af-input-border-focus: var(--af-color-info);
    --af-input-placeholder-color: rgba(0, 0, 0, 0.45);
  }
</style>

<div class="af-field">
  <label class="af-field__label" for="input-custom">Name</label>
  <input id="input-custom" class="af-input" placeholder="Ada Lovelace" />
</div>

Inputs use --af-input-radius, which defaults to --af-control-radius and then --af-radius. Set --af-radius on :root to round fields, cards, and buttons together. Override --af-input-radius only when fields should be tighter or squarer than boxed UI.

<style>
  :root {
    --af-radius: var(--af-radius-sm);
  }
</style>

<div class="af-stack input-radius-sm-demo">
  <div class="af-field">
    <label class="af-field__label" for="input-radius-email">Email</label>
    <input id="input-radius-email" class="af-input" placeholder="ada@example.com" />
  </div>
  <button type="button" class="af-btn">Continue</button>
</div>

Required for accessibility: When showing errors, you must:

  1. Set aria-invalid="true" on the input
  2. Link the error message via aria-describedby (input references error message id)
<div class="af-field">
  <label class="af-field__label" for="input-invalid-email">Email</label>
  <input
  type="email"
  id="input-invalid-email"
  class="af-input af-is-error"
  aria-invalid="true"
  aria-describedby="input-invalid-email-error"
  placeholder="ada@example.com"
/>
  <div class="af-field__error" id="input-invalid-email-error">Please enter a valid email address</div>
</div>