Video examples

iOS Voiceover

Android Talkback

MacOS Voiceover Safari

Code examples

Use semantic HTML

  • This semantic HTML contains all accessibility features by default.
  • It uses CSS pseudo attributes to create the radio indicator, no Javascript.
<fieldset>
  <legend>
    Choose the best NATO letter
  </legend>

  <input type="radio" name="nato" id="alphaRadio">
  <label for="alphaRadio">Alpha</label>

  <input type="radio" name="nato" id="bravoRadio">
  <label for="bravoRadio">Bravo</label>

  <input type="radio" name="nato" id="charlieRadio" aria-describedby="description-charlie" checked>
  <label for="charlieRadio">Charlie</label>
  <div class="description" id="description-charlie">The best at everything</div>
</fieldset>
Choose the best NATO letter
The best at everything

Fully disabled radio inputs

<fieldset>
  <legend>
    Choose your favorite coffee chain
  </legend>

  <input type="radio" name="coffee" id="dunkinRadio">
  <label for="dunkinRadio">Dunkin'</label>

  <input type="radio" name="coffee" id="dutchRadio" checked>
  <label for="dutchRadio">Dutch Brothers</label>

  <input type="radio" name="coffee" id="starbucksRadio" disabled>
  <label for="starbucksRadio">Starbucks</label>
</fieldset>
Choose your favorite coffee chain

Disabled and focusable radio inputs

It’s possible to use aria-disabled="true" so screen reader users can focus the radio button with the arrow keys. Use preventDefault() to prevent the checkbox from being checked.

When specific radio inputs are conditionally enabled/disabled by other controls in the page this method can make ensure all radio input options are discoverable.

<fieldset>
  <legend>
    Choose your favorite dance
  </legend>

  <input type="radio" name="dance" id="carltonRadio" aria-disabled="true">
  <label for="carltonRadio">Carlton</label>

  <input type="radio" name="dance" id="foxtrotRadio">
  <label for="foxtrotRadio">Foxtrot</label>

  <input type="radio" name="dance" id="tangoRadio" checked>
  <label for="tangoRadio">Tango</label>
</fieldset>
Choose your favorite dance

Required radio inputs

Ensuring all screenreaders indicate radio inputs as being required requires some aria and reinforcement.

  • Use aria-required="true" to indicate the group is required
  • Use aria-invalid="true/false" to indicate an error state
  • Add role="radiogroup" to the <fieldset> to make the aria-required attribute valid
  • Add “Required” as text to the <legend> to ensure compliance across all platforms
<fieldset aria-required="true" 
          aria-invalid="true" 
          role="radiogroup">
  <legend>
    Choose your second favorite NATO letter <span>Required</span>
  </legend>

  <input type="radio" name="natoReq" id="deltaRadioReq">
  <label for="deltaRadioReq">Delta</label>

  <input type="radio" name="natoReq" id="echoRadioReq">
  <label for="echoRadioReq">Echo</label>

  <input type="radio" name="natoReq" id="foxtrotRadioReq">
  <label for="foxtrotRadioReq">Foxtrot</label>
</fieldset>
Choose your second favorite NATO letter Required

Radio button cards

<ul class="cards">
  <li class="card interactive">
    <input type="radio"
           name="radioCards"
           id="deltaRadioCard"
           aria-describedby="description-deltaRadioCard" >
    <label for="deltaRadioCard">
      Delta
    </label>
    <div class="extended-description"
         id="description-deltaRadioCard">
      Delta (prounounced: <strong>dell</strong>-tah)
      is the fourth letter of the NATO alphabet.
    </div>
  </li>
  <li class="card interactive">
    <input type="radio"
           name="radioCards"
           id="echoRadioCard"
           aria-describedby="description-echoRadioCard">
    <label for="echoRadioCard">Echo</label>
    <div class="extended-description"
         id="description-echoRadioCard">
      Echo (prounounced: <strong>eck</strong>-oh)
      is the fifth letter of the NATO alphabet.
    </div>
  </li>
</ul>
  • Delta (prounounced: dell-tah) is the fourth letter of the NATO alphabet.
  • Echo (prounounced: eck-oh) is the fifth letter of the NATO alphabet.

When you can’t use semantic HTML

This custom button requires extra scripting work for roving tabindex and event listeners.

<custom-label id="labelId">
    Which is your favorite NATO letter:
</custom-label>
<div role="radiogroup" aria-labelledby="labelId">
  <custom-element role="radio" tabindex="-1">
    Alpha
  </custom-element>
  <custom-element role="radio" tabindex="-1">
    Bravo
  </custom-element>
  <custom-element role="radio" tabindex="-1">
    Charlie
  </custom-element>  
</div>

Specialty use cases

Radio mixed with interactive elements

Avoid placing interactive elements between radio buttons.

  • Radio button focus order is not what you think it is.
  • When nothing is selected, tab order moves through as expected.
  • However, as soon as a radio button is selected, the selected radio input receives focus first from the group.

Checkbox radio hack

  • This hack must be used very carefully on a case by case basis.
  • With great power comes great responsibility.
<fieldset class="checkbox-radio-group">
  <legend>Choose your payment method:</legend>
  <input class="radio"
         type="checkbox"
         role="radio"
         name="checkboxRadioGroup"
         id="checkboxRadioAlpha"
         aria-describedby="editAlpha"
         checked>
  <label for="checkboxRadioAlpha">
    Alpha
  </label>
  <button type="button"
          class="tertiary"
          id="editAlpha">
    Edit
    <span class="hidden">
      payment method alpha
    </span>
  </button>

  <input  class="radio"
          type="checkbox"
          role="radio"
          name="checkboxRadioGroup"
          id="checkboxRadioBravo"
          aria-describedby="editBravo">
  <label for="checkboxRadioBravo">
    Bravo
  </label>
  <button type="button"
          class="tertiary"
          id="editBravo">
    Edit
    <span class="hidden">
      payment method Bravo
    </span>
  </button>

  <input class="radio"
         type="checkbox"
         role="radio"
         name="checkboxRadioGroup"
         id="checkboxRadioCharlie"
         aria-describedby="editCharlie">
  <label for="checkboxRadioCharlie">
    Charlie
  </label>
  <button type="button"
          class="tertiary"
          id="editCharlie">
    Edit
    <span class="hidden">
      payment method Charlie
    </span>
  </button>
</fieldset>
Choose your payment method:

Thanks

Related radio button entries