CSS-Only

Checkbox

Native checkbox and radio inputs with custom styling, semantic variants, sizes, and states. Accessible by default with proper label association.

Example

<label class="omni-checkbox">
  <input type="checkbox" name="example1">
  <span>Accept terms and conditions</span>
</label>

<label class="omni-checkbox">
  <input type="checkbox" name="example2" checked>
  <span>Subscribe to newsletter</span>
</label>

<label class="omni-checkbox">
  <input type="checkbox" name="example3" disabled>
  <span>Disabled option</span>
</label>

Checkboxes

Basic Checkboxes

Use the wrapper <label> pattern for proper accessibility:

Indeterminate State

JavaScript can set the indeterminate state for partial selections:

// Set indeterminate state via JavaScript
const checkbox = document.getElementById('parent-checkbox');
checkbox.indeterminate = true;

Sizes

Use data-size to adjust checkbox dimensions:

<label class="omni-checkbox" data-size="sm">
  <input type="checkbox" name="size1" checked>
  <span>Small checkbox</span>
</label>

<label class="omni-checkbox" data-size="lg">
  <input type="checkbox" name="size3" checked>
  <span>Large checkbox</span>
</label>

Required State

Required checkboxes show validation styling when unchecked:

<label class="omni-checkbox">
  <input type="checkbox" name="required" required>
  <span>I agree <span aria-hidden="true">*</span></span>
</label>

Readonly State

Readonly checkboxes are visible but not interactive:

Radio Buttons

Basic Radio Group

Radio buttons should be grouped with <fieldset> and <legend>:

Preferred contact method
<fieldset class="omni-radio-group">
  <legend>Preferred contact method</legend>
  <label class="omni-radio">
    <input type="radio" name="contact" value="email" checked>
    <span>Email</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="contact" value="phone">
    <span>Phone</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="contact" value="sms">
    <span>SMS</span>
  </label>
</fieldset>

Radio Sizes

Use data-size on the label wrapper:

Disabled Radio

Group Layouts

Vertical Layout (Default)

Groups stack vertically by default:

Horizontal Layout

Use data-layout="horizontal" for inline groups:

<div class="omni-checkbox-group" data-layout="horizontal">
  <label class="omni-checkbox">...</label>
  <label class="omni-checkbox">...</label>
  <label class="omni-checkbox">...</label>
</div>

Fieldset Group

Use <fieldset> for semantic grouping with legend:

Select your interests
<fieldset class="omni-checkbox-group">
  <legend>Select your interests</legend>
  <label class="omni-checkbox">...</label>
  <label class="omni-checkbox">...</label>
</fieldset>

API Reference

Checkbox / Radio Classes

Class Element Description
.omni-checkbox <label> Wrapper for checkbox input
.omni-radio <label> Wrapper for radio input
.omni-checkbox-group <div> or <fieldset> Container for multiple checkboxes
.omni-radio-group <div> or <fieldset> Container for multiple radio buttons

Data Attributes

Attribute Values Default Description
data-size sm, md, lg md Input size (applies to label)
data-layout horizontal Group layout direction (applies to group container)

Native Input States

Attribute Description
checked Input is selected
disabled Input is disabled and cannot be interacted with
required Input must be checked (shows validation styling)
readonly Input is visible but not interactive
indeterminate Set via JavaScript: checkbox.indeterminate = true

Accessibility

  • Label Association: Always wrap inputs in <label> elements for proper association. Clicking the label toggles the input.
  • Keyboard Navigation: Full keyboard support (Tab, Space to toggle)
  • Focus Indicators: Clear focus rings for keyboard navigation
  • Radio Groups: Use <fieldset> and <legend> to group related radio buttons semantically
  • Required Fields: Use native required attribute for validation. Add visual asterisk with aria-hidden="true"
  • Validation: Browser-native validation states show danger color when required checkbox is unchecked
  • Disabled State: Native disabled attribute prevents interaction and is announced by screen readers
  • Readonly State: Use readonly attribute to display checked state without allowing changes
  • Color Contrast: All states meet WCAG 2.1 Level AA contrast requirements
  • Indeterminate State: Provides visual feedback for partial selections in hierarchical lists

Best Practices

<!-- ✅ GOOD: Proper label association -->
<label class="omni-checkbox">
  <input type="checkbox" name="agree">
  <span>I agree to terms</span>
</label>

<!-- ✅ GOOD: Radio group with fieldset -->
<fieldset class="omni-radio-group">
  <legend>Choose payment method</legend>
  <label class="omni-radio">
    <input type="radio" name="payment" value="card">
    <span>Credit Card</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="payment" value="paypal">
    <span>PayPal</span>
  </label>
</fieldset>

<!-- ✅ GOOD: Required with accessible asterisk -->
<label class="omni-checkbox">
  <input type="checkbox" name="terms" required>
  <span>I agree <span aria-hidden="true">*</span></span>
</label>

<!-- ❌ BAD: Missing label association -->
<input type="checkbox" id="bad">
<label for="bad">Checkbox</label>