CSS-Only

Radio

Native radio input with custom styling. Works with semantic fieldsets and supports sizes and variants. Always use within a group for mutually exclusive selections.

Example

Preferred contact method
<fieldset>
  <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="mail">
    <span>Mail</span>
  </label>
</fieldset>

Variants

Sizes

Use data-size on the label to adjust radio dimensions:

Small
Medium (default)
Large
<label class="omni-radio" data-size="sm">
  <input type="radio" name="size" value="1">
  <span>Small size</span>
</label>

<label class="omni-radio">
  <input type="radio" name="size" value="2">
  <span>Default size</span>
</label>

<label class="omni-radio" data-size="lg">
  <input type="radio" name="size" value="3">
  <span>Large size</span>
</label>

States

Disabled

Options
<label class="omni-radio">
  <input type="radio" name="option" value="1" disabled>
  <span>Disabled option</span>
</label>

Required

Required radios show validation states. The browser will prevent form submission if no option is selected:

Choose a plan
<fieldset>
  <legend>Choose a plan <span aria-hidden="true">*</span></legend>
  <label class="omni-radio">
    <input type="radio" name="plan" value="basic" required>
    <span>Basic</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="plan" value="pro" required>
    <span>Pro</span>
  </label>
</fieldset>

Readonly

Readonly radios are visible but not interactive:

Selected plan (locked)
<label class="omni-radio">
  <input type="radio" name="plan" value="pro" checked readonly>
  <span>Pro (selected, locked)</span>
</label>

Group Layouts

Vertical (default)

Radio groups are vertical by default:

Shipping method
<fieldset class="omni-radio-group">
  <legend>Shipping method</legend>
  <label class="omni-radio">
    <input type="radio" name="shipping" value="standard" checked>
    <span>Standard (5-7 days)</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="shipping" value="express">
    <span>Express (2-3 days)</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="shipping" value="overnight">
    <span>Overnight</span>
  </label>
</fieldset>

Horizontal

Use data-layout="horizontal" on the group container for inline layout:

Size
<fieldset class="omni-radio-group" data-layout="horizontal">
  <legend>Size</legend>
  <label class="omni-radio">
    <input type="radio" name="size" value="small">
    <span>Small</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="size" value="medium" checked>
    <span>Medium</span>
  </label>
  <label class="omni-radio">
    <input type="radio" name="size" value="large">
    <span>Large</span>
  </label>
</fieldset>

API Reference

Label Attributes

Attribute Values Default Description
data-size sm, md, lg md Radio button size

Input Attributes

Attribute Type Description
name string Required. Groups related radios together (all radios in a group must share the same name)
value string Required. The value submitted when this radio is selected
checked boolean Marks this radio as selected by default
disabled boolean Prevents interaction with this radio
required boolean Requires one radio in the group to be selected before form submission
readonly boolean Makes the radio visible but not interactive

Group Container Attributes

Attribute Values Default Description
data-layout horizontal vertical Layout direction for radio group

Accessibility

  • Always wrap radio groups in a <fieldset> with a <legend> to provide context
  • Each radio must have an associated <label> using the wrapper pattern
  • All radios in a group must share the same name attribute
  • Full keyboard navigation: Tab to enter group, arrow keys to select options, Space to check
  • Focus visible indicators with clear contrast
  • Disabled state prevents interaction and conveys state visually with reduced opacity
  • Required validation shows red border when no option is selected
  • Readonly state makes radios visible but non-interactive (useful for locked selections)
  • Native browser behavior ensures proper announcements to screen readers
  • Use aria-hidden="true" on decorative asterisks for required fields

Best Practices

  • Use radios when users must select exactly one option from a set
  • For 2-5 options, consider horizontal layout for better visual grouping
  • For 6+ options, stick with vertical layout for easier scanning
  • If no default selection is appropriate, don't use checked on any option
  • Use descriptive labels that clearly communicate what each option means
  • Group related radios with semantic <fieldset> and <legend>

Components Used

Other OmniUI components demonstrated on this page: