Forms
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:
<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.
<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:
<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
forattribute that matches the input'sid - Place checkboxes and radios inside label elements for automatic association
When visible labels aren't possible:
- Visually hidden labels using the
.visually-hiddenutility class - Reference existing content with
aria-labelledby - Add descriptive
titleattributes (not recommended as primary method) - Use
aria-labelfor 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
requiredattribute 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;