Forms

Native HTML form elements styled automatically — no extra classes on inputs, labels, or textareas. The framework handles spacing, focus states, validation, and dark mode.

Complete Contact Form

<form>
  <label for="name">Full Name <span aria-hidden="true">*</span></label>
  <input type="text" id="name" name="name" autocomplete="name" required>

  <label for="email">Email <span aria-hidden="true">*</span></label>
  <input type="email" id="email" name="email" autocomplete="email" required>

  <label for="subject">Subject</label>
  <select id="subject" name="subject">
    <option value="">Choose a subject…</option>
    <option value="support">Support</option>
  </select>

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <button type="submit" class="primary">Send</button>
  <button type="reset" class="secondary">Clear</button>
</form>

Validation States

Axiom01 uses native HTML5 validation states (`:invalid:not(:placeholder-shown)`) to automatically highlight errors when a user leaves an invalid field, without requiring custom JS or extra classes.

<!-- Just use native HTML5 validation attributes (type="email", required) -->
<label for="email">Email Address</label>
<input type="email" id="email" value="invalid-email@" required>

Modifiers

  • `form.centered` - Limits the form's maximum width and centers it using margins.

All Input Types

<!-- All types are styled automatically — no classes needed -->
<label for="date">Date</label>
<input type="date" id="date">

<label for="time">Time</label>
<input type="time" id="time">

<label for="vol">Volume</label>
<input type="range" id="vol" min="0" max="100" value="50">

<label for="file">File Upload</label>
<input type="file" id="file" accept=".pdf,.doc">

Textarea

Set rows for initial height. The browser allows vertical resize via resize: vertical (applied by default). Use maxlength + <output> for character counts:

<label for="bio">Bio</label>
<textarea id="bio" rows="4" maxlength="280"></textarea>

Select & Option Groups

<label for="plan">Plan</label>
<select id="plan">
  <option value="">Choose…</option>
  <option value="free">Free</option>
  <option value="pro">Pro</option>
</select>

<!-- Grouped options -->
<select id="stack">
  <optgroup label="Frontend">
    <option>React</option>
  </optgroup>
  <optgroup label="Backend">
    <option>Node.js</option>
  </optgroup>
</select>

Checkboxes & Radio Buttons

Notification preferences
Account type
<!-- Always wrap in fieldset + legend -->
<fieldset>
  <legend>Notifications</legend>
  <label>
    <input type="checkbox" name="notify" value="email" checked>
    Email notifications
  </label>
  <label>
    <input type="checkbox" name="notify" value="sms">
    SMS notifications
  </label>
</fieldset>

<fieldset>
  <legend>Account type</legend>
  <label>
    <input type="radio" name="type" value="personal" checked>
    Personal
  </label>
  <label>
    <input type="radio" name="type" value="team">
    Team
  </label>
</fieldset>

Validation States

Use aria-invalid + aria-describedby for accessible error states. A helper <small> element provides context text:

Please enter a valid email address.
Username is available.
Minimum 8 characters. Include a number and a symbol.
Account IDs cannot be changed after creation.
<!-- Error state -->
<label for="email">Email</label>
<input type="email" id="email" value="bad-email"
       aria-invalid="true"
       aria-describedby="email-error">
<small id="email-error">
  <span class="axicon render" data-name="Alert-Circle"></span>
  Please enter a valid email address.
</small>

<!-- With helper text -->
<label for="pw">Password</label>
<input type="password" id="pw" aria-describedby="pw-hint">
<span id="pw-hint">Minimum 8 characters.</span>

Required Fields Pattern

Fields marked are required.

<p><small>Fields marked * are required.</small></p>

<label for="name">Name <span aria-hidden="true">*</span></label>
<input type="text" id="name" required>

<!-- The * is aria-hidden — required attr does the accessible work -->

Inline Search Form

For single-line inline forms, wrap input + button in a <div class="actions">:

<label for="search">Search documentation</label>
<div class="actions">
  <input type="search" id="search" placeholder="Search…">
  <button type="submit" class="primary">
    <span class="axicon render" data-name="Search"></span> Search
  </button>
</div>

Native Validation with JavaScript

const form = document.querySelector('form');

form.addEventListener('submit', e => {
  e.preventDefault();

  // Validate all fields
  const fields = form.querySelectorAll('input, select, textarea');
  let firstInvalid = null;

  fields.forEach(field => {
    const valid = field.checkValidity();
    field.setAttribute('aria-invalid', !valid);

    // Show/hide associated error message
    const errorId = field.getAttribute('aria-describedby');
    if (errorId) {
      const errorEl = document.getElementById(errorId);
      if (errorEl) errorEl.hidden = valid;
    }

    if (!valid && !firstInvalid) firstInvalid = field;
  });

  if (firstInvalid) {
    firstInvalid.focus(); // Move focus to first error
    return;
  }

  // All valid — submit
  const data = new FormData(form);
  console.log(Object.fromEntries(data));
});

Design Philosophy

  • No extra classes on inputs — all types styled via input[type="..."] element selectors
  • Label always paired — use for/id or wrap the input inside the label
  • fieldset + legend — always group related checkboxes and radios
  • Native validation firstrequired, type, min, max, pattern
  • aria-describedby — connect error/helper text to the input by id
  • autocomplete — always set for common fields (name, email, address)
  • No .form-control, .form-group, .input-wrapper — these are anti-patterns in Axiom01

Accessibility

  • Every input must have a visible <label> — placeholder text disappears and is not a label
  • Required fields: use required attribute (not CSS-only asterisks)
  • Error messages: use aria-invalid="true" on the input + aria-describedby pointing to the error text
  • Error text container should have role="alert" for immediate announcement
  • Disabled fields use the disabled attribute — never CSS pointer-events: none only
  • Group related controls in <fieldset> with a <legend>
  • Touch targets minimum 44×44px — the framework ensures this for all inputs
  • Focus styles are always visible — never suppress :focus-visible

Features

  • Semantic Structure - Built with native HTML5 elements for maximum reliability.
  • Theme Aware - Automatically adapts to all 22 Axiom01 themes via OKLCH tokens.
  • Fully Responsive - Scales perfectly from mobile to desktop screens.
  • No JS Dependency - Core functionality relies on pure CSS for maximum performance.
  • Customizable - Easily extendable via Axiom01's design tokens and modifiers.

Use Cases

The Forms component is designed for versatile implementation across modern web applications. Ideal scenarios include:

  • Dashboards & Admin Panels - Structured data presentation and interface control.
  • Content Management Systems - Organizing complex information hierarchies and media.
  • E-Commerce Platforms - Enhancing product discovery and user workflows.
  • Marketing Sites - Highlighting key product offerings cleanly and effectively.
  • SaaS Applications - Delivering native-feeling, responsive app experiences.