One last time: custom styling radio buttons and checkboxes

About three years ago now (2017/2018), I published a collection of accessible styled form controls which included specific markup patterns to create custom styled radio buttons and checkboxes. These patterns were the culmination of years of my own tinkering, studying other people’s implementations, and then stress testing them with the assistive technologies I had at my disposal.


This content originally appeared on Scott O’Hara UX developer, designer & accessibility engineer and was authored by Scott O'Hara

About three years ago now (2017/2018), I published a collection of accessible styled form controls which included specific markup patterns to create custom styled radio buttons and checkboxes. These patterns were the culmination of years of my own tinkering, studying other people’s implementations, and then stress testing them with the assistive technologies I had at my disposal.

At the time, the most robust way to style these form contrls, without re-creating them from scratch with ARIA, was to visually hide the radio button or checkbox, and then recreate the controls using a <label> or <span> and their pseudo-elements (::before and ::after). The need for this approach was largely, but not entirely, due to Internet Explorer and Legacy Edge not providing the best support to directly style native HTML <input> elements themselves. And if you go even further back in time, all browsers had barries in directly styling these controls.

That’s not to say, in 2018, that directly styling native radio buttons and checkboxes couldn’t be done (see restyled radio buttons) and restyled checkboxes). But there were workarounds needed, and styling limitations that still existed due to inconsistencies with Firefox, Internet Explorer, and pre-Chromium Edge, at the time.

Now (2021), with Internet Explorer support being dropped left and right, and Edge now being Chromium-based, and Firefox quirks having been ironed out, these limitations have largely lifted.

I hope this is the last time I write about this subject.

What’s necessary to directly restyle radios and checkboxes?

As we are going to style the elements directly, the expected markup patterns would be the same as if you were not applying custom styling. For instance:

<label for="r1">
  <input type="radio" id="r1" name="r">
  Restyle Option 
</label>
<!-- or -->
<input type="radio" id="r2" name="r">
<label for="r2">Resyle option</label>
<label for="c1">
  <input type="checkbox" id="c1">
  Choice 2
</label>
<!-- or -->
<input type="checkbox" id="c2">
<label for="c2">
  Choice 2
</label>

The necessary CSS

There are a varieity of CSS properties that radio buttons and checkboxes will respect by default, but to start absolutely fresh (which, if you’re restyling these controls that’s probably what you want anyway), the first thing we need to do is clear them of all default styling. For this, we use the appearance: none property.

Note: for these particular components, I have not run into any unforseen issues with using the unprefixed appearance property. But, according to caniuse.com, Webkit still requires a -webkit- prefix. Generally best to be safe than sorry, so while annoying to still need both the prefixed -webkit-appearance and apperance, might as well keep it up for now.

Once apperance: none is specified for the radio buttons and checkboxes you’re going to revise, you’ll have full styling control over the element itself, and its ::before an ::after pseudo elements. But, now that you’ve taken on this task, you have the following you need to account for in your CSS:

  • Default (unchecked state).
  • New checked state.
  • Custom focus state.
  • Checked state focus style (if the previous focus style is not noticable against the new checked style - e.g., dark outline against a new dark fill when the control is checked).
  • Disabled state (make sure the label text continues to meet necessary contrast minimums!).
  • Make sure left-to-right and right-to-left (dir=ltr, dir=rtl) was not impacted by any of your styling.
  • Verify your styling works with Media Queries such as

You can play around with the following radio button and checkbox CodePen. Try adding dir=rtl to the containing <div> elements, or set one of the controls to disabled.

See the Pen Custom Styled Native Radio Button by Scott (@scottohara) on CodePen.

Beyond the necessary CSS and markup

Maybe you’re thinking you need more than what’s been called out here. Three selectors to style a radio button or checkbox? “Psh”, you exclaim. “I have some serious user delight that needs injecting into these mundane controls for performing basic tasks on the Internet.” Cool! Feel free to add in other generic/presentational elements as you see fit.

For instance:

<div class="custom-check-container">
  <input type="checkbox" id="c">
  <span class="blip-bloop" aria-hidden="true"></span>
  <span class="bleep-blop" aria-hidden="true"></span>
  <label for="c">
    Choice
  </label>
</div>

<!--
  Regarding the aria-hidden=true on the span elements. 
  You may well not "need" these to be explicitly set to be
  hidden from the browser's accessibility tree... but as
  I have no idea what one might do with these decorative
  elements, seems best to put up some guard rails.
-->

The markup above has wrapped the checkbox within a containng <div> element, and two extra <span> elements with silly class names have been added for additional styling flourishes. E.g., want to make an animation effect when hovering, focusing or activating your checkbox? Now you can use CSS sibling selectors (e.g, ~ or +) and/or some JavaScript to get your Material Design on (just remember to be careful with your z-indexing so these extra <span> elements don’t accidently block a click or touch event from reaching your form control).

Just, whatever you do, you don’t need to do something silly like this:

<div role=checkbox aria-checked=false tabindex=0>
  <input type=checkbox tabindex=-1 aria-hidden=true>
  <div>
    <!-- oodles of divs -->
    Name of control
  </div>
</div>

Nesting interactive elements like the above is absolutely unnecessary, and depending on the assistive technology used, the “hidden” checkbox may still be discoverable (for instance, navigating line-by-line with VoiceOver on macOS, or using Dragon Naturally Speaking - as recent testing has uncovered).

If you find yourself stuck in a situation where you are dealing with the above invalid nesting of a checkbox within a ‘checkbox’, you likely use CSS visibility: hidden to competely hide the nested native checkbox from assistive technologies, while still maintaining your present functionality. A refactor would be ideal here, as the CSS we ship is a strong suggestion, but not a requirement for users. But hey, sometimes you just gotta hide your mistake and hope that no one peaks under your rug and notices all piles of dirt and dust. Right?

Wrap up and acknowledgements

At this point, I’m seeing very few reasons to continue to recommend the visually-hidden technique to style radio buttons and checkboxes. With all modern browsers being able to handle the styling of these controls, the visually hidden technique has far too many extra gotchas, though managable, to be aware of and account for.

Additionally, I’m also quite skeptical of the “need” to create custom ARIA radio buttons and checkboxes. The level of effort to make these custom controls, and ensure all necessary functionality is present, goes far beyond just needing to update one’s CSS. Even if you needed to create an ARIA role=switch, CSS styling and relying on an <input type=checkbox>’s implicit checked functionality would give you all that you need to style a native checkbox into a custom switch (the third example on this linked page).

For additional information on styling native radio buttons and checkboxes, particularlly using the visually-hidden technique, I recommend reviewing the following:


This content originally appeared on Scott O’Hara UX developer, designer & accessibility engineer and was authored by Scott O'Hara


Print Share Comment Cite Upload Translate Updates
APA

Scott O'Hara | Sciencx (2021-09-24T00:00:00+00:00) One last time: custom styling radio buttons and checkboxes. Retrieved from https://www.scien.cx/2021/09/24/one-last-time-custom-styling-radio-buttons-and-checkboxes/

MLA
" » One last time: custom styling radio buttons and checkboxes." Scott O'Hara | Sciencx - Friday September 24, 2021, https://www.scien.cx/2021/09/24/one-last-time-custom-styling-radio-buttons-and-checkboxes/
HARVARD
Scott O'Hara | Sciencx Friday September 24, 2021 » One last time: custom styling radio buttons and checkboxes., viewed ,<https://www.scien.cx/2021/09/24/one-last-time-custom-styling-radio-buttons-and-checkboxes/>
VANCOUVER
Scott O'Hara | Sciencx - » One last time: custom styling radio buttons and checkboxes. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/09/24/one-last-time-custom-styling-radio-buttons-and-checkboxes/
CHICAGO
" » One last time: custom styling radio buttons and checkboxes." Scott O'Hara | Sciencx - Accessed . https://www.scien.cx/2021/09/24/one-last-time-custom-styling-radio-buttons-and-checkboxes/
IEEE
" » One last time: custom styling radio buttons and checkboxes." Scott O'Hara | Sciencx [Online]. Available: https://www.scien.cx/2021/09/24/one-last-time-custom-styling-radio-buttons-and-checkboxes/. [Accessed: ]
rf:citation
» One last time: custom styling radio buttons and checkboxes | Scott O'Hara | Sciencx | https://www.scien.cx/2021/09/24/one-last-time-custom-styling-radio-buttons-and-checkboxes/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.