Accessible Styled Form Controls

Styled Radio Button Star Rating Component

Published:

Last updated:

Pattern to restyle a radio button group into a star rating component.

Pattern Demo

Rate my rating system:
Disabled (via fieldset) my rating system:
Rate my rating system (some inputs disabled):

Pattern Details

Pattern Markup
<fieldset class="r-radios">
  <legend>
    Rate my rating system:
  </legend>

  <input type="radio" name="r_input" id="r_input_0" checked>
  <label for="r_input_0" class="r-radio r-radio--none">
    <svg aria-hidden="true" focusable="false">
      <use xlink:href="#no_rating"/>
    </svg>
    <span>No rating</span>
  </label>

  <input type="radio" name="r_input" id="r_input_1">
  <label for="r_input_1" class="r-radio">
    <svg aria-hidden="true" focusable="false">
      <use xlink:href="#star"/>
    </svg>
    <span>1 Star</span>
  </label>

  <!-- add more stars here! -->
</fieldset>

As the rating system is built by a series of radio buttons, these form controls should live within a fieldset with a legend to appropriately caption the radio button group's purpose. If it makes sense for these groupings of radio buttons to be called out in the document outline, then the legend can have an appropriately ranked heading element as its child element, containing the text of the legend.

The ratings begin with a "No rating" radio button that has is set to the checked attribute, by default. Radio buttons do not have a native way to revert to a completely unchecked state, without usage of a form reset button or a user performing a hard refresh with their browser. If a user erroneously "rates" an item, there should be a way for them to negate that rating without having to reset a form or refresh the page, hence the "No rating" option.

The actual radio button input elements are visually hidden, but maintain the ability to be focused and found by keyboard and screen reader users. The label for each radio button contains an inline SVG of a star, so the SVG can be manipulated by CSS. A text string is also contained within the label and is visible on :hover and :focus of the SVG and input, respectively.

Note that the SVG elements have the following attributes:

  • aria-hidden="true" to hide the SVG from screen readers.
  • focusable="false" to ensure that Internet Explorer does not allow keyboard focus to attempt to traverse the SVG.

Affects on Screen Reader Announcements?

Since the native radio buttons remain in the DOM, and are used as the focusable elements that control the state of their custom visualization, there are no alterations to how a screen reader announces keyboard focused styled radio buttons.

Using standard visually hidden CSS to hide the native radio button off screen, or as a single pixel in the document, will mean that certain screen reader users might be unable to locate the radio button. For instance, those searching by touch, or using a mouse while a screen reader announces what is being hovered. To mitigate this, the radio buttons have been positioned on top of their styled labels, yet still styled to be visually hidden. Note that NVDA does not announce the radio button role when hovered by mouse, regardless of it being styled or not, unless default NVDA settings are changed.

When a radio button is receives keyboard focus, screen readers like JAWS and NVDA may automatically go into forms mode, or require a user to hit Enter or Space to focus into the radio button, depending on the user's settings. Then arrow keys can be used to select the different radio buttons, as expected in forms mode.

VoiceOver on macOS may begin to focus the radio button labels when using arrow keys to change the selected radio button. This issue does not exist in VoiceOver + Chrome and is not necessarily unique to this particular styling of radio buttons.

Continue Reading

For another take on star rating radio groups, with a bunch of style variants, check out the Starability project by Lunar Logic.