Skip to main contentSkip to docs navigation

Checkboxes and Radio Buttons

Create accessible, customized checkboxes and radio buttons with Chassis CSS's enhanced form controls.

@layer components
MDN Reference
Component tokens

Overview

Chassis CSS replaces browser default checkboxes and radios with custom-styled controls that maintain accessibility while providing consistent appearance across browsers and devices.

It is possible to use both the traditional sibling <input> and <label> elements connected with id and for attributes and nested <input> elements within <label> elements for more compact markup. Both approaches look identical and maintain full accessibility, letting you choose the pattern that works best for your project.

Usage

The .form-check component creates controls that look consistent across browsers while supporting accessibility, different sizes, and various layouts. Use the .check-input class on the <input type="checkbox"> or <input type="radio"> element to apply Chassis CSS's custom styles, and wrap it with a .form-check container for proper spacing and alignment.

Checkboxes

Use .check-input class on the <input type="checkbox"> element and wrap it with a .form-check container for proper spacing and alignment.

HTML
<!-- Sibling markup pattern -->
<div class="form-check">
  <input class="check-input" type="checkbox" id="checkSibling">
  <label for="checkSibling">Sibling checkbox</label>
</div>

<!-- Nested markup pattern -->
<label class="form-check">
  <input class="check-input" type="checkbox" id="checkNested" checked>
   Nested checkbox
</label>

Radio buttons

Using type="radio" creates radio buttons, which allow users to select only one option from a group. Like checkboxes, radio buttons can be styled with Chassis CSS for a consistent look and feel.

HTML
<label class="form-check">
  <input class="check-input" type="radio" name="radioExample">
  Option one
</label>
<label class="form-check">
  <input class="check-input" type="radio" name="radioExample" checked>
  Option two
</label>

Indeterminate state

The indeterminate state provides a third visual state for checkboxes, useful for indicating partially selected options or group selections. Since HTML has no attribute for this state, it must be set via JavaScript using the indeterminate property.

HTML
<label class="form-check">
  <input class="check-input" type="checkbox" value="" id="checkIndeterminate">
  Indeterminate checkbox
</label>

Disabled state

Apply the HTML disabled attribute to indicate that a checkbox is unavailable for interaction. Chassis CSS automatically styles both the checkbox and its label with visual cues to indicate the disabled state.

HTML
<label class="form-check">
  <input class="check-input" type="checkbox" value="" id="checkDisabled" disabled>
  Disabled checkbox
</label>
<label class="form-check">
  <input class="check-input" type="checkbox" value="" id="checkCheckedDisabled" checked disabled>
  Disabled checked checkbox
</label><label class="form-check">
  <input class="check-input" type="checkbox" value="" id="checkIndeterminateDisabled" disabled>
  Disabled indeterminate checkbox
</label>
<label class="form-check">
  <input class="check-input" type="radio" value="" id="radioDisabled" disabled>
  Disabled radio
</label>
<label class="form-check">
  <input class="check-input" type="radio" value="" id="radioCheckedDisabled" checked disabled>
  Disabled checked radio
</label>

Switches

Chassis CSS offers toggle switches as an alternative UI for boolean (on/off) selections. Switches are built on checkbox markup but with enhanced styling via the .form-switch class.

Adding the role="switch" attribute improves accessibility by correctly communicating the control's purpose to assistive technologies that support this role. In older assistive technologies, it will simply be announced as a regular checkbox as a fallback. Switches also support the disabled attribute.

HTML
<label class="form-check form-switch">
  <input class="check-input" type="checkbox" role="switch" id="switchCheckDefault">
  Default switch checkbox input
</label>
<label class="form-check form-switch">
  <input class="check-input" type="checkbox" role="switch" id="switchCheckChecked" checked>
  Checked switch checkbox input
</label>
<label class="form-check form-switch">
  <input class="check-input" type="checkbox" role="switch" id="switchCheckDisabled" disabled>
  Disabled switch checkbox input
</label>
<label class="form-check form-switch">
  <input class="check-input" type="checkbox" role="switch" id="switchCheckCheckedDisabled" checked disabled>
  Disabled checked switch checkbox input
</label>

Descriptive labels

For interface designs that require controls without visible text labels, omit the wrapping .form-check container. While this creates a visually minimal control, remember that all form elements must still have an accessible name for screen reader users (see forms overview accessibility).

HTML
<label class="form-check">
  <input class="check-input" type="checkbox">
  Checkbox with description
  <small class="form-help">
    This is a helpful description for the checkbox.
  </small>
</label>
<label class="form-check">
  <input class="check-input" type="checkbox">
  Checkbox with inline description
  <small class="form-help fg-subtle d-inline">
    – This is an inline help text for the checkbox.
  </small>
</label>

Without visible labels

For interface designs that require controls without visible text labels, omit the wrapping .form-check container. While this creates a visually minimal control, remember that all form elements must still have an accessible name for screen reader users (see forms overview accessibility).

HTML
<input class="check-input" type="checkbox" id="checkboxNoLabel" value="" aria-label="Subscribe to newsletter">
<input class="check-input" type="radio" name="radioNoLabel" id="radioNoLabel1" value="1" aria-label="Select first option">
<input class="check-input" type="radio" name="radioNoLabel" id="radioNoLabel2" value="2" aria-label="Select second option">

Sizing options

Add .small or .large classes to change the size of form check.

HTML
<div class="form-check large">
  <input class="check-input" type="checkbox" id="checkLarge">
  <label class="check-label" for="checkLarge">
    Large checkbox
  </label>
</div>
<div class="form-check">
  <input class="check-input" type="checkbox" id="checkMedium">
  <label class="check-label" for="checkMedium">
    Default checkbox
  </label>
</div>
<div class="form-check small">
  <input class="check-input" type="checkbox" id="checkSmall">
  <label class="check-label" for="checkSmall">
    Small checkbox
  </label>
</div>

Sizing also works on switches. Add .small or .large classes to the .form-check.form-switch container to adjust the size of the switch and its label together.

HTML
<label class="form-check form-switch large">
  <input class="check-input" type="radio" name="radioSize" id="switchLarge">
    Large switch
</label>
<label class="form-check form-switch">
  <input class="check-input" type="radio" name="radioSize" id="switchMedium" checked>
  Default switch
</label>
<label class="form-check form-switch small">
  <input class="check-input" type="radio" name="radioSize" id="switchSmall">
  Small switch
</label>

Sizing without labels

When using checkboxes or radios without visible labels, you can apply .small or .large classes directly to the input element to adjust the size of the control itself.

HTML
<input class="check-input large" type="checkbox">
<input class="check-input" type="checkbox">
<input class="check-input small" type="checkbox">
  <span class="vr mx-medium"></span>
<input class="check-input large" name="radioSizeInput" type="radio">
<input class="check-input" name="radioSizeInput" type="radio">
<input class="check-input small" name="radioSizeInput" type="radio">
  <span class="vr mx-medium"></span>
<input class="check-input large" role="switch" name="switchSizeInputLarge" type="checkbox">
<input class="check-input" role="switch" name="switchSizeInputMedium" type="checkbox">
<input class="check-input small" role="switch" name="switchSizeInputSmall" type="checkbox">

Layout options

By default, .form-check elements stack vertically with appropriate spacing, creating a clean, readable list of checks.

Inline layout

Use flex utilities to create inline layouts for checkboxes and radio buttons when you want to save vertical space or create a more compact form design. This allows multiple controls to be displayed on the same line while maintaining proper spacing and alignment.

HTML
<div class="d-flex gap-medium">
  <label class="form-check">
    <input class="check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1">
    Option one
  </label>
  <label class="form-check">
    <input class="check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2">
    Option two
  </label>
  <label class="form-check">
    <input class="check-input" type="radio" name="inlineRadioOptions" id="inlineRadio3" value="option3" disabled>
    Option three (disabled)
  </label>
</div>

Reversed layout

Use the .reverse modifier class to position the control on the right side of the label. This layout is useful for maintaining visual alignment with surrounding content or creating specific UI patterns.

HTML
<div class="form-check reverse">
  <input class="check-input" type="checkbox" value="" id="reverseCheck1">
  <label class="check-label" for="reverseCheck1">
    Reverse checkbox
  </label>
</div>
<div class="form-check reverse">
  <input class="check-input" type="checkbox" value="" id="reverseCheck2" disabled>
  <label class="check-label" for="reverseCheck2">
    Disabled reverse checkbox
  </label>
</div>

<div class="form-check form-switch reverse">
  <input class="check-input" type="checkbox" role="switch" id="switchCheckReverse">
  <label class="check-label" for="switchCheckReverse">Reverse switch checkbox input</label>
</div>

Button checks

Chassis CSS provides a way to style checkboxes and radio buttons as buttons, combining the semantic meaning of form controls with the visual appearance of buttons. These controls use the .button-check class on the input and .button styles on the corresponding <label> elements.

Checkbox toggles

Checkbox button toggles allow users to toggle checks on and off with a button-like appearance. They maintain the same states and behaviors as standard checkboxes but with enhanced visual styling.

HTML
<label class="button button-check default">
  <input type="checkbox" autocomplete="off">
  Button check
</label>
<label class="button button-check default">
  <input type="checkbox" checked autocomplete="off">
  Checked
</label>
<label class="button button-check default">
  <input type="checkbox" autocomplete="off" disabled>
  Disabled
</label>

From an accessibility perspective, button-styled checkboxes are announced by screen readers as "checkbox checked"/"checkbox not checked" since they maintain their semantic role. This differs from toggle buttons created with the button component, which are announced as "button"/"button pressed". Choose the appropriate approach based on whether the control's purpose is better communicated as a state change (checkbox) or an action trigger (button).

Radio toggles

Radio button toggles provide a button-styled interface for mutually exclusive selections. They offer the same semantic meaning as standard radio buttons but with an enhanced visual appearance that may be more suitable for certain UI patterns.

HTML
<label class="button button-check default">
  <input type="radio" name="options" autocomplete="off" checked>
  Checked
</label>
<label class="button button-check default">
  <input type="radio" name="options" autocomplete="off">
  Radio
</label>
<label class="button button-check default">
  <input type="radio" name="options" autocomplete="off" disabled>
  Disabled
</label>
<label class="button button-check default">
  <input type="radio" name="options" autocomplete="off">
  Radio
</label>

Style variants

Chassis CSS's button-styled toggles support all visual variants available to standard buttons. This includes outlined styles, which provide a lower-emphasis alternative that still clearly communicates the interactive nature of the control.

HTML
<label class="button button-check default">
  <input type="radio" name="styleOptions" autocomplete="off">
  Default
</label>
<label class="button button-check primary">
  <input type="radio" name="styleOptions" checked autocomplete="off">
  Primary
</label>
<label class="button button-check primary smooth">
  <input type="radio" name="styleOptions" autocomplete="off" checked>
  Primary smooth
</label>
<label class="button button-check secondary outline">
  <input type="radio" name="styleOptions" autocomplete="off">
  Secondary outlined
</label>

Modern Inputs

Chassis CSS's checkboxes and radio buttons can use contextual color classes to create custom-styled controls that fit your design. This allows you to apply any of the available color variants to the check and radio indicators while maintaining the same structure and accessibility.

By default; both $enable-form-check-legacy and $enable-form-check-modern are set to true, allowing you to use either the legacy or modern check styles. It is recommended to choose one approach, and disable the unused styles in your Sass configuration to reduce CSS bundle size. See the options page for details on how to enable or disable specific form styles.

Usage patterns

Wrap the <input> element with a .check-input container and apply the desired context color class to the container. This pattern works with both nested and sibling markup structures, giving you flexibility in how you structure your form controls.

HTML
<!-- Nested input pattern -->
<label class="form-check">
  <span class="check-input secondary">
    <input type="checkbox" id="checkNestedModern" checked>
  </span>
  Nested input with secondary context color
</label>

<!-- Sibling input pattern -->
<div class="form-check">
  <span class="check-input secondary">
    <input type="checkbox" id="checkSiblingModern" checked>
  </span>
  <label for="checkSiblingModern">Sibling input with secondary context color</label>
</div>

Context variants

Use any of the available context color classes to create custom-styled checkboxes and radio buttons that fit your design. This allows you to maintain the same structure and accessibility while applying different visual styles to the controls.

HTML
<label class="form-check">
  <span class="check-input default"><input type="checkbox" checked></span>
  Default checkbox
</label>
<label class="form-check">
  <span class="check-input alternate"><input type="checkbox" checked></span>
  Alternate checkbox
</label>
<label class="form-check">
  <span class="check-input primary"><input type="checkbox" checked></span>
  Primary checkbox
</label>
<label class="form-check">
  <span class="check-input secondary"><input type="checkbox" checked></span>
  Secondary checkbox
</label>
<label class="form-check">
  <span class="check-input neutral"><input type="checkbox" checked></span>
  Neutral checkbox
</label>
<label class="form-check">
  <span class="check-input danger"><input type="checkbox" checked></span>
  Danger checkbox
</label>
<label class="form-check">
  <span class="check-input success"><input type="checkbox" checked></span>
  Success checkbox
</label>
<label class="form-check">
  <span class="check-input warning"><input type="checkbox" checked></span>
  Warning checkbox
</label>
<label class="form-check">
  <span class="check-input info"><input type="checkbox" checked></span>
  Info checkbox
</label>
<label class="form-check">
  <span class="check-input black"><input type="checkbox" checked></span>
  Black checkbox
</label>
<label class="form-check">
  <span class="check-input white"><input type="checkbox" checked></span>
  White checkbox
</label>

Disabled inputs

Disabled state styling also works with custom context colors. Apply the disabled attribute to the <input> element, and Chassis CSS will automatically adjust the styles of both the checkbox/radio and its label to indicate the disabled state while maintaining the chosen context color.

HTML
<span class="check-input default">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input alternate">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input primary">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input secondary">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input neutral">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input danger">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input success">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input warning">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input info">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input black">
  <input type="checkbox" checked disabled>
</span>
<span class="check-input white">
  <input type="checkbox" checked disabled>
</span>

Radio buttons

HTML
<span class="check-input default">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input alternate">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input primary">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input secondary">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input neutral">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input danger">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input success">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input warning">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input info">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input black">
    <input type="radio" name="radioContext">
  </span>
<span class="check-input white">
    <input type="radio" name="radioContext">
  </span>

Indeterminate checks

HTML
<span class="check-input default">
  <input type="checkbox" id="checkdefaultIndeterminate">
</span>
<span class="check-input alternate">
  <input type="checkbox" id="checkalternateIndeterminate">
</span>
<span class="check-input primary">
  <input type="checkbox" id="checkprimaryIndeterminate">
</span>
<span class="check-input secondary">
  <input type="checkbox" id="checksecondaryIndeterminate">
</span>
<span class="check-input neutral">
  <input type="checkbox" id="checkneutralIndeterminate">
</span>
<span class="check-input danger">
  <input type="checkbox" id="checkdangerIndeterminate">
</span>
<span class="check-input success">
  <input type="checkbox" id="checksuccessIndeterminate">
</span>
<span class="check-input warning">
  <input type="checkbox" id="checkwarningIndeterminate">
</span>
<span class="check-input info">
  <input type="checkbox" id="checkinfoIndeterminate">
</span>
<span class="check-input black">
  <input type="checkbox" id="checkblackIndeterminate">
</span>
<span class="check-input white">
  <input type="checkbox" id="checkwhiteIndeterminate">
</span>

Switch role

HTML
<label class="form-check form-switch">
  <span class="check-input default">
    <input type="checkbox" role="switch" checked>
  </span>
  Default switch
</label>
<label class="form-check form-switch">
  <span class="check-input alternate">
    <input type="checkbox" role="switch" checked>
  </span>
  Alternate switch
</label>
<label class="form-check form-switch">
  <span class="check-input primary">
    <input type="checkbox" role="switch" checked>
  </span>
  Primary switch
</label>
<label class="form-check form-switch">
  <span class="check-input secondary">
    <input type="checkbox" role="switch" checked>
  </span>
  Secondary switch
</label>
<label class="form-check form-switch">
  <span class="check-input neutral">
    <input type="checkbox" role="switch" checked>
  </span>
  Neutral switch
</label>
<label class="form-check form-switch">
  <span class="check-input danger">
    <input type="checkbox" role="switch" checked>
  </span>
  Danger switch
</label>
<label class="form-check form-switch">
  <span class="check-input success">
    <input type="checkbox" role="switch" checked>
  </span>
  Success switch
</label>
<label class="form-check form-switch">
  <span class="check-input warning">
    <input type="checkbox" role="switch" checked>
  </span>
  Warning switch
</label>
<label class="form-check form-switch">
  <span class="check-input info">
    <input type="checkbox" role="switch" checked>
  </span>
  Info switch
</label>
<label class="form-check form-switch">
  <span class="check-input black">
    <input type="checkbox" role="switch" checked>
  </span>
  Black switch
</label>
<label class="form-check form-switch">
  <span class="check-input white">
    <input type="checkbox" role="switch" checked>
  </span>
  White switch
</label>

Sizing

Apply .small or .large classes to the .form-check container to adjust the size of the checkbox or radio button while maintaining the same context color styling.

HTML
<label class="form-check large">
  <span class="check-input secondary">
    <input type="checkbox" checked>
  </span>
  Large checkbox
</label>
<label class="form-check">
  <span class="check-input secondary">
    <input type="checkbox" checked>
  </span>
  Default checkbox
</label>
<label class="form-check small">
  <span class="check-input secondary">
    <input type="checkbox" checked>
  </span>
  Small checkbox
</label>
<label class="form-check large">
  <span class="check-input secondary">
    <input type="checkbox" role="switch" checked>
  </span>
  Large switch
</label>
<label class="form-check">
  <span class="check-input secondary">
    <input type="checkbox" role="switch" checked>
  </span>
  Default switch
</label>
<label class="form-check small">
  <span class="check-input secondary">
    <input type="checkbox" role="switch" checked>
  </span>
  Small switch
</label>
HTML
<span class="check-input secondary small">
  <input type="checkbox" name="checkContextSizeSmall">
</span>
<span class="check-input secondary">
  <input type="checkbox" name="checkContextSizeMedium">
</span>
<span class="check-input secondary large">
  <input type="checkbox" name="checkContextSizeLarge">
</span>
  <span class="vr mx-medium"></span>
<span class="check-input secondary small">
  <input type="radio" name="radioContextSize">
</span>
<span class="check-input secondary">
  <input type="radio" name="radioContextSize">
</span>
<span class="check-input secondary large">
  <input type="radio" name="radioContextSize">
</span>
  <span class="vr mx-medium"></span>
<span class="check-input secondary small">
  <input type="checkbox" role="switch" name="switchContextSizeSmall">
</span>
<span class="check-input secondary">
  <input type="checkbox" role="switch" name="switchContextSizeMedium">
</span>
<span class="check-input secondary large">
  <input type="checkbox" role="switch" name="switchContextSizeLarge">
</span>

Accessibility considerations

Chassis CSS's checkbox and radio components are designed with accessibility in mind, but there are several best practices to follow for optimal user experience:

When presenting multiple related options, use the <fieldset> and <legend> elements to create a semantic grouping:

HTML
<fieldset>
  <legend>Choose your delivery preferences:</legend>
  <div class="form-check">
    <input class="check-input" type="checkbox" id="optEmail">
    <label class="check-label" for="optEmail">Email notifications</label>
  </div>
  <div class="form-check">
    <input class="check-input" type="checkbox" id="optSMS">
    <label class="check-label" for="optSMS">SMS notifications</label>
  </div>
</fieldset>

Focus visibility

Chassis CSS provides visible focus indicators for all form controls. Do not remove these indicators, as they are essential for keyboard users to navigate your forms.

State communication

The different visual states of checkboxes and radio buttons (checked, unchecked, indeterminate, disabled) are designed to be perceivable through:

  • Visual design (color, shape changes)
  • High contrast ratios between states
  • Non-reliance on color alone to communicate state

For more detailed accessibility guidance, see the forms overview accessibility section.

CSS

Chassis CSS uses a powerful combination of Sass and CSS variables to create a flexible form system that adapts to themes and design requirements.

This component can be customized through Sass variables at compile time.

Custom properties

Check the overview page to see the CSS variables shared by all form elements.

Sass variables

This component uses Sass variables in scss/config/_defaults.scss to define its defaults.


These variables control the appearance of checkboxes and radio buttons:

$form-check-medium-size:                $icon-small;
$form-check-large-size:                 $icon-medium;
$form-check-small-size:                 $icon-xsmall;

$form-check-medium-gap:                 $space-xsmall;
$form-check-large-gap:                  $space-small;
$form-check-small-gap:                  $space-2xsmall;

$form-check-border-width:               $form-regular-border-width;
$form-check-checkbox-border-radius:     $border-radius-small;
$form-check-radio-border-radius:        50%;

$form-check-min-height:                 null;
$form-check-transition:                 null;

$form-check-checked-fg-color:           $default-fg-active;
$form-check-checked-bg-color:           $default-cue-main;
$form-check-checked-border-color:       $form-check-checked-bg-color;

$form-check-disabled-label-color:       var(--fg-subtle);
$form-check-focus-ring-offset:          $form-input-focus-ring-offset;

These variables specifically affect the appearance of toggle switches:

$form-switch-idle-color:                $form-idle-fg-inactive;
$form-switch-disabled-color:            $form-disabled-fg-inactive;
$form-switch-focus-color:               $form-idle-fg-active;
$form-switch-checked-color:             $form-check-checked-fg-color;

$form-switch-medium-width:                     2rem;
$form-switch-medium-height:                    1.25rem;
$form-switch-medium-toggle-width:              1rem;
$form-switch-medium-toggle-height:             1rem;

$form-switch-small-width:                     1.5rem;
$form-switch-small-height:                    1rem;
$form-switch-small-toggle-width:              .75rem;
$form-switch-small-toggle-height:             .75rem;

$form-switch-large-width:                     2.5rem;
$form-switch-large-height:                    1.5rem;
$form-switch-large-toggle-width:              1.25rem;
$form-switch-large-toggle-height:             1.25rem;


$form-switch-toggle-border-radius:      var(--border-radius-full);
$form-switch-border-radius:             var(--border-radius-full);

$form-switch-icon:                      "<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='currentcolor'/></svg>";
// $form-switch-checked-icon-position:     100%;
$form-switch-transition:                background-position .15s ease-in-out;

Design tokens

This component consumes design tokens from Chassis Tokens with the $cx- prefix. — See thedesign tokens page.


The following design tokens define the check and radio indicators for various states:

$form-check-checkbox-icon:                $cx-icon-form-input-check-checkbox;
$form-check-indeterminate-icon:           $cx-icon-form-input-check-indeterminate;
$form-check-radio-icon:                   $cx-icon-form-input-check-radio;

Check the overview page to see the design tokens shared by all form elements.