Skip to main content Skip to docs navigation

Create accessible, responsive forms with Chassis CSS's comprehensive suite of form components, styling options, and validation features.

Overview

Chassis CSS provides a complete form styling system built on modern CSS practices. The framework enhances the base form styles in the Reboot module with specialized classes for consistent rendering across browsers and devices.

Form components utilize CSS variables for theming, making them highly customizable while maintaining visual consistency. This approach allows easy adaptation to different design systems and color schemes.

Always use appropriate HTML5 type attributes on input elements (e.g., email, number, tel) to leverage built-in browser validation and specialized input controls for better user experience.

Here's a basic example demonstrating Chassis CSS form elements:

We'll never share your email with anyone else.
html
<form>
  <div class="mb-medium">
    <label for="exampleInputEmail1" class="form-label">Email address</label>
    <input type="email" class="form-input" id="exampleInputEmail1" aria-describedby="emailHelp">
    <div id="emailHelp" class="form-help">We'll never share your email with anyone else.</div>
  </div>
  <div class="mb-medium">
    <label for="exampleInputPassword1" class="form-label">Password</label>
    <input type="password" class="form-input" id="exampleInputPassword1">
  </div>
  <div class="mb-medium form-check">
    <input type="checkbox" class="check-input" id="exampleCheck1">
    <label class="check-label" for="exampleCheck1">Check me out</label>
  </div>
  <button type="submit" class="button primary">Submit</button>
</form>

Disabled forms

Apply the disabled boolean attribute to an input element to prevent user interactions and provide visual feedback by changing its appearance.

<input class="form-input" id="disabledInput" type="text" placeholder="Disabled input here..." disabled>

To disable multiple form controls at once, add the disabled attribute to a parent <fieldset> element. All native form elements (<input>, <select>, and <button>) within a disabled fieldset will be programmatically disabled and visually styled accordingly.

For custom interactive elements like <a class="button"> within a disabled fieldset, Chassis CSS applies pointer-events: none to prevent mouse interactions. However, for complete accessibility, you should manually add tabindex="-1" to prevent keyboard focus and aria-disabled="disabled" to communicate the disabled state to assistive technologies.

Disabled fieldset example
html
<form>
  <fieldset disabled>
    <legend>Disabled fieldset example</legend>
    <div class="mb-medium">
      <label for="disabledTextInput" class="form-label">Disabled input</label>
      <input type="text" id="disabledTextInput" class="form-input" placeholder="Disabled input">
    </div>
    <div class="mb-medium">
      <label for="disabledSelect" class="form-label">Disabled select menu</label>
      <select id="disabledSelect" class="form-select">
        <option>Disabled select</option>
      </select>
    </div>
    <div class="mb-medium">
      <div class="form-check">
        <input class="check-input" type="checkbox" id="disabledFieldsetCheck">
        <label class="check-label" for="disabledFieldsetCheck">
          Can't check this
        </label>
      </div>
    </div>
    <button type="submit" class="button primary">Submit</button>
  </fieldset>
</form>

Dark mode

Chassis CSS forms automatically adapt to dark mode environments using CSS variables that respond to theme context. When the data-cx-theme="dark" attribute is applied to a container or directly to form elements, the styling smoothly transitions to a dark-optimized palette that maintains accessibility and visual hierarchy.

Inheritance and override

Form elements inherit their theme from parent elements but can be individually themed by applying the data-cx-theme attribute directly to specific inputs:

  • Apply data-cx-theme="dark" to a container for all child form controls to adopt dark mode
  • Apply data-cx-theme="light" to specific inputs within a dark container to create visual emphasis

The example below demonstrates applying contrasting themes with individual controls and containers:

html
<div class="row gap-xlarge">
  <form class="col context p-medium" data-cx-theme="light">
    <div class="mb-medium">
      <label for="exampleInputEmailDark" class="form-label">Email address</label>
      <input type="email" class="form-input" id="exampleInputEmailDark" aria-describedby="emailHelp" data-cx-theme="dark">
    </div>
    <div class="mb-medium">
      <label for="exampleInputPasswordDark" class="form-label">Password</label>
      <input type="password" class="form-input" id="exampleInputPasswordDark" data-cx-theme="dark">
    </div>
    <div class="mb-medium form-check">
      <input type="checkbox" class="check-input" id="exampleCheckDark" data-cx-theme="dark">
      <label class="check-label" for="exampleCheckDark">Check me out</label>
    </div>
    <button type="submit" class="button primary">Submit</button>
  </form>

  <form class="col context p-medium" data-cx-theme="dark">
    <div class="mb-medium">
      <label for="exampleInputEmailLight" class="form-label">Email address</label>
      <input type="email" class="form-input" id="exampleInputEmailLight" aria-describedby="emailHelp" data-cx-theme="light">
    </div>
    <div class="mb-medium">
      <label for="exampleInputPasswordLight" class="form-label">Password</label>
      <input type="password" class="form-input" id="exampleInputPasswordLight" data-cx-theme="light">
    </div>
    <div class="mb-medium form-check">
      <input type="checkbox" class="check-input" id="exampleCheckLight" data-cx-theme="light">
      <label class="check-label" for="exampleCheckLight">Check me out</label>
    </div>
    <button type="submit" class="button primary">Submit</button>
  </form>
</div>

For best performance, apply theme attributes to container elements rather than individual form controls whenever possible. This reduces DOM complexity and improves rendering efficiency.

Accessibility

Creating accessible forms is essential for users of assistive technologies. Chassis CSS form components are designed with accessibility in mind, but proper implementation requires attention to the following principles:

Accessible naming techniques

Every form control must have an accessible name that clearly communicates its purpose to assistive technology users. Without proper naming, users of screen readers and other assistive devices cannot understand what information is being requested.

Use explicit labels

  • Connect inputs with labels using the for attribute that matches the input's id
  • Place checkboxes and radios inside label elements for automatic association

When visible labels aren't possible:

  • Visually hidden labels using the .visually-hidden utility class
  • Reference existing content with aria-labelledby
  • Add descriptive title attributes (not recommended as primary method)
  • Use aria-label for concise, explicit naming

Never rely solely on placeholder attributes for accessible naming, as placeholders:

  • Disappear when the field contains content
  • Often have low color contrast
  • Cannot be accessed by all assistive technologies consistently

State communication

Form controls should communicate their states (required, invalid, disabled) both visually and programmatically:

  • Use the required attribute for mandatory fields
  • Implement aria-invalid="true" for validation errors
  • Ensure error messages are associated with their fields using aria-describedby

For detailed implementation guidance, refer to the accessibility section in each form component's documentation.

CSS

Chassis CSS forms use a comprehensive system of CSS variables to enable consistent styling and easy theming. The framework applies a state-based approach where form elements adapt their appearance based on:

  • Idle state (default appearance)
  • Focus state (when interacted with)
  • Disabled state (when not available)
  • Validation states (valid, invalid)

These states are implemented through CSS custom properties (variables) with predictable naming patterns:

/* Example of state-based CSS variables */
--cx-idle-bg-regular: #fff;       /* Standard input background in idle state */
--cx-idle-bg-floating: #eee;      /* Floating label input background in idle state */
--cx-disabled-fg-active: #999;    /* Text color in disabled state */
--cx-disabled-fg-inactive: #ccc;  /* Placeholder color in disabled state */
--cx-focus-border-color: #00f;    /* Border color in focus state */
--cx-invalid-help-color: #f00;  /* Text & icon color for validation feedbacks */

Custom properties

These CSS variables are part of Chassis CSS's design token system, giving design teams control over component appearance. See the design tokens page for more details.

// Idle state variables
// Form inputs in their default state
--#{$prefix}form-idle-bg-regular: #{$form-idle-bg-regular};
--#{$prefix}form-idle-fg-active: #{$form-idle-fg-active};
--#{$prefix}form-idle-fg-inactive: #{$form-idle-fg-inactive};
--#{$prefix}form-idle-border-color: #{$form-idle-border-color};
--#{$prefix}form-idle-help-color: #{$form-idle-help-color};
--#{$prefix}form-idle-bg-floating: #{$form-idle-bg-floating};

// Focus state variables
// Applied when the input receives focus
--#{$prefix}form-focus-bg-regular: #{$form-focus-bg-regular};
--#{$prefix}form-focus-fg-active: #{$form-focus-fg-active};
--#{$prefix}form-focus-fg-inactive: #{$form-focus-fg-inactive};
--#{$prefix}form-focus-border-color: #{$form-focus-border-color};
--#{$prefix}form-focus-help-color: #{$form-focus-help-color};
--#{$prefix}form-focus-bg-floating: #{$form-focus-bg-floating};

// Disabled state variables
// Applied when the input is disabled
--#{$prefix}form-disabled-bg-regular: #{$form-disabled-bg-regular};
--#{$prefix}form-disabled-fg-active: #{$form-disabled-fg-active};
--#{$prefix}form-disabled-fg-inactive: #{$form-disabled-fg-inactive};
--#{$prefix}form-disabled-border-color: #{$form-disabled-border-color};
--#{$prefix}form-disabled-help-color: #{$form-disabled-help-color};
--#{$prefix}form-disabled-bg-floating: #{$form-disabled-bg-floating};

// Error validation state variables
// Applied for invalid input validation
--#{$prefix}form-invalid-bg-regular: #{$form-invalid-bg-regular};
--#{$prefix}form-invalid-fg-active: #{$form-invalid-fg-active};
--#{$prefix}form-invalid-fg-inactive: #{$form-invalid-fg-inactive};
--#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};
--#{$prefix}form-invalid-help-color: #{$form-invalid-help-color};
--#{$prefix}form-invalid-bg-floating: #{$form-invalid-bg-floating};

// Success validation state variables
// Applied for valid input validation
--#{$prefix}form-valid-bg-regular: #{$form-valid-bg-regular};
--#{$prefix}form-valid-fg-active: #{$form-valid-fg-active};
--#{$prefix}form-valid-fg-inactive: #{$form-valid-fg-inactive};
--#{$prefix}form-valid-border-color: #{$form-valid-border-color};
--#{$prefix}form-valid-help-color: #{$form-valid-help-color};
--#{$prefix}form-valid-bg-floating: #{$form-valid-bg-floating};

// Special input component styling
// File input button styling
--#{$prefix}file-button-fg-color: #{$form-file-button-fg-color};
--#{$prefix}file-button-bg-image: #{$form-file-button-bg-image};
--#{$prefix}file-button-bg-color: #{$form-file-button-bg-color};
--#{$prefix}file-button-bg-hover: #{$form-file-button-bg-hover};

// Input addon styling (for input groups)
--#{$prefix}input-addon-fg-color: #{$form-input-addon-fg-color};
--#{$prefix}input-addon-bg-image: #{$form-input-addon-bg-image};
--#{$prefix}input-addon-bg-color: #{$form-input-addon-bg-color};
--#{$prefix}input-addon-border-color: #{$form-input-addon-border-color};

// Range input styling
--#{$prefix}form-range-track-color: #{$form-range-track-color};
--#{$prefix}form-range-thumb-color: #{$form-range-thumb-color};
--#{$prefix}form-range-thumb-disabled: #{$form-range-thumb-disabled};
--#{$prefix}form-range-thumb-active: #{$form-range-thumb-active};

// Default box shadow that changes based on validation states
--#{$prefix}form-focus-box-shadow: #{$form-input-focus-box-shadow};

Design Tokens

These design tokens with $cx prefixes are managed by design teams in Figma using the Tokens Studio plugin. See the design tokens page for more details.


Typography tokens define consistent font properties across all form elements:

$form-medium-label-font:                  $cx-font-form-input-medium-label;
$form-large-label-font:                   $cx-font-form-input-large-label;
$form-small-label-font:                   $cx-font-form-input-small-label;
$form-medium-text-font:                   $cx-font-form-input-medium-text;
$form-large-text-font:                    $cx-font-form-input-large-text;
$form-small-text-font:                    $cx-font-form-input-small-text;
$form-floating-text-font:                 $cx-font-form-input-floating-text;
$form-floating-label-font:                $cx-font-form-input-floating-label;

Spacing tokens ensure consistent dimensions and proportions across form controls:

$form-medium-padding-y:                   $cx-space-form-input-medium-padding-y;
$form-medium-padding-x:                   $cx-space-form-input-medium-padding-x;
$form-medium-gap:                         $cx-space-form-input-medium-gap;
$form-large-padding-y:                    $cx-space-form-input-large-padding-y;
$form-large-padding-x:                    $cx-space-form-input-large-padding-x;
$form-large-gap:                          $cx-space-form-input-large-gap;
$form-small-padding-y:                    $cx-space-form-input-small-padding-y;
$form-small-padding-x:                    $cx-space-form-input-small-padding-x;
$form-small-gap:                          $cx-space-form-input-small-gap;

Border tokens provide visual definition and interactive state indicators for form controls:

$form-regular-border-width:               $cx-border-width-form-input-regular;
$form-floating-border-width:              $cx-border-width-form-input-floating;

$form-medium-border-radius:               $cx-border-radius-form-input-medium;
$form-large-border-radius:                $cx-border-radius-form-input-large;
$form-small-border-radius:                $cx-border-radius-form-input-small;

$form-floating-border-radius-t:           $cx-border-radius-form-input-floating-blunt;
$form-floating-border-radius-b:           $cx-border-radius-form-input-floating-sharp;

Color tokens establish visual hierarchy and communicate state changes in form elements:

$form-idle-bg-regular:            $cx-color-form-input-idle-bg-regular;
$form-idle-bg-floating:           $cx-color-form-input-idle-bg-floating;
$form-idle-fg-active:             $cx-color-form-input-idle-fg-active;
$form-idle-fg-inactive:           $cx-color-form-input-idle-fg-inactive;
$form-idle-border-color:          $cx-color-form-input-idle-border;
$form-idle-help-color:            $cx-color-form-input-idle-help;
$form-idle-caret-color:           $cx-color-form-input-idle-caret;

$form-disabled-bg-regular:        $cx-color-form-input-disabled-bg-regular;
$form-disabled-bg-floating:       $cx-color-form-input-disabled-bg-floating;
$form-disabled-fg-active:         $cx-color-form-input-disabled-fg-active;
$form-disabled-fg-inactive:       $cx-color-form-input-disabled-fg-inactive;
$form-disabled-border-color:      $cx-color-form-input-disabled-border;
$form-disabled-help-color:        $cx-color-form-input-disabled-help;
$form-disabled-caret-color:       $cx-color-form-input-disabled-caret;

$form-focus-bg-regular:           $cx-color-form-input-focus-bg-regular;
$form-focus-bg-floating:          $cx-color-form-input-focus-bg-floating;
$form-focus-fg-active:            $cx-color-form-input-focus-fg-active;
$form-focus-fg-inactive:          $cx-color-form-input-focus-fg-inactive;
$form-focus-border-color:         $cx-color-form-input-focus-border;
$form-focus-help-color:           $cx-color-form-input-focus-help;
// $form-focus-caret-color:          $cx-color-form-input-focus-caret;

$form-invalid-bg-regular:         $cx-color-form-input-error-bg-regular;
$form-invalid-bg-floating:        $cx-color-form-input-error-bg-floating;
$form-invalid-fg-active:          $cx-color-form-input-error-fg-active;
$form-invalid-fg-inactive:        $cx-color-form-input-error-fg-inactive;
$form-invalid-border-color:       $cx-color-form-input-error-border;
$form-invalid-help-color:         $cx-color-form-input-error-help;
// $form-invalid-caret-color:        $cx-color-form-input-error-caret;

$form-valid-bg-regular:           $cx-color-form-input-success-bg-regular;
$form-valid-bg-floating:          $cx-color-form-input-success-bg-floating;
$form-valid-fg-active:            $cx-color-form-input-success-fg-active;
$form-valid-fg-inactive:          $cx-color-form-input-success-fg-inactive;
$form-valid-border-color:         $cx-color-form-input-success-border;
$form-valid-help-color:           $cx-color-form-input-success-help;
// $form-valid-caret-color:          $cx-color-form-input-success-caret;