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" autocomplete="current-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-input">
<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="exampleSelectDark" class="form-label">Example Select</label>
<select class="form-input" id="exampleSelectDark" data-cx-theme="dark">
<option selected>Choose an option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</div>
<div class="mb-medium">
<label for="exampleInputDark" class="form-label">Example Input</label>
<input type="text" class="form-input" id="exampleInputDark" data-cx-theme="dark" placeholder="Dark themed input">
</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">Example checkbox</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="exampleSelectLight" class="form-label">Example Select</label>
<select class="form-input" id="exampleSelectLight" data-cx-theme="light">
<option selected>Choose an option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</div>
<div class="mb-medium">
<label for="exampleInputLight" class="form-label">Example Input</label>
<input type="text" class="form-input" id="exampleInputLight" data-cx-theme="light" placeholder="Light themed input">
</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">Example checkbox</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
Form components can be customized through Sass variables at compile time.
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:
These states are implemented through CSS custom properties (variables) with predictable naming patterns:
/* Example of state-management */
.form-element {
--bg-color: var(--input-bg-color, var(--form-idle-bg-regular));
background-color: var(--bg-color);
}
.form-element:disabled {
--input-bg-color: var(--form-disabled-bg-regular);
}Custom properties
Form components expose CSS custom properties to control their appearance at runtime.
Color properties for form elements that adapt to state changes:
--fg-color: var(--input-fg-color, var(--form-idle-fg-active));
--bg-color: var(--input-bg-color, var(--form-idle-bg-regular));
--border-color: var(--input-border-color, var(--form-idle-border-color));
--icon-color: var(--input-icon-color, var(--form-idle-fg-active));Color properties control the visual appearance of all form elements across different states:
// Idle state colors
--form-idle-bg-regular: #{$form-idle-bg-regular};
--form-idle-fg-active: #{$form-idle-fg-active};
--form-idle-fg-inactive: #{$form-idle-fg-inactive};
--form-idle-border-color: #{$form-idle-border-color};
--form-idle-help-color: #{$form-idle-help-color};
--form-idle-bg-floating: #{$form-idle-bg-floating};
// Focus state colors
--form-focus-bg-regular: #{$form-focus-bg-regular};
--form-focus-fg-active: #{$form-focus-fg-active};
--form-focus-fg-inactive: #{$form-focus-fg-inactive};
--form-focus-border-color: #{$form-focus-border-color};
--form-focus-help-color: #{$form-focus-help-color};
--form-focus-bg-floating: #{$form-focus-bg-floating};
// Disabled state colors
--form-disabled-bg-regular: #{$form-disabled-bg-regular};
--form-disabled-fg-active: #{$form-disabled-fg-active};
--form-disabled-fg-inactive: #{$form-disabled-fg-inactive};
--form-disabled-border-color: #{$form-disabled-border-color};
--form-disabled-help-color: #{$form-disabled-help-color};
--form-disabled-bg-floating: #{$form-disabled-bg-floating};
// Invalid state colors
--form-invalid-bg-regular: #{$form-invalid-bg-regular};
--form-invalid-fg-active: #{$form-invalid-fg-active};
--form-invalid-fg-inactive: #{$form-invalid-fg-inactive};
--form-invalid-border-color: #{$form-invalid-border-color};
--form-invalid-help-color: #{$form-invalid-help-color};
--form-invalid-bg-floating: #{$form-invalid-bg-floating};
// Valid state colors
--form-valid-bg-regular: #{$form-valid-bg-regular};
--form-valid-fg-active: #{$form-valid-fg-active};
--form-valid-fg-inactive: #{$form-valid-fg-inactive};
--form-valid-border-color: #{$form-valid-border-color};
--form-valid-help-color: #{$form-valid-help-color};
--form-valid-bg-floating: #{$form-valid-bg-floating};
// Default focus ring color that changes based on validation states
--form-focus-ring-color: #{$form-input-focus-ring-color};
--form-valid-focus-ring-color: #{$form-valid-focus-ring-color};
--form-invalid-focus-ring-color: #{$form-invalid-focus-ring-color};Sizing and spacing properties ensure consistent dimensions and proportions for form controls:
@include map-font($form-medium-text-font, input);
--padding-x: var(--input-padding-x, #{$form-medium-padding-x});
--padding-y: var(--input-padding-y, #{$form-medium-padding-y});
--gap: var(--input-gap, #{$form-medium-gap});
--min-height: var(--input-min-height, #{$form-input-min-height});
--border-width: var(--input-border-width, #{$form-regular-border-width});
--border-radius: var(--input-border-radius, #{$form-medium-border-radius});
--caret-size: var(--input-caret-size, #{$form-medium-caret-size});
--icon-size: var(--input-icon-size, #{$form-medium-icon-size});Sass variables
This component uses Sass variables in scss/config/_defaults.scss to define its defaults.
$form-input-plaintext-color: var(--fg-main);
$form-input-min-height: calc(var(--line-height) + var(--padding-y) * 2);
$form-input-box-shadow: none; // var(--box-shadow-inset);
$form-input-focus-ring-color: $focus-ring-color;
$form-input-focus-ring-offset: 0px;
$form-input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;Design Tokens
Form components consume design tokens from Chassis Tokens with the $cx- prefix. — See thedesign tokens page.
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-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-width: $cx-border-width-form-input-floating;
$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;