Create custom keyboard accessible radio buttons
Tags: html, css, a11y
Published: 2019-08-05 19:40:10

---
title: Create custom keyboard accessible radio buttons
published: true
description: 
tags: html, css, a11y
canonical_url: https://www.a11ywithlindsey.com/blog/create-custom-keyboard-accessible-radio-buttons
cover_image: https://thepracticaldev.s3.amazonaws.com/i/xxnjwk96aclkf7creq97.png
---

_Originally posted on [a11ywithlindsey.com](https://www.a11ywithlindsey.com/blog/create-custom-keyboard-accessible-radio-buttons)._

Hey friends! Today we'll be creating custom keyboard accessible radio buttons! This blog post is a follow-up post from [my accessible checkboxes post](https://www.a11ywithlindsey.com/blog/create-custom-keyboard-accesible-checkboxes).

We'll go over:

1. The markup
1. Creating a pseudo-element on the label in CSS
1. Add "selected" styling in CSS
1. Add focus styling

## Starting out

I decided to create a simple group of radio buttons asking what your favorite animal is

```html
<fieldset>
  <legend>What is your favorite Wild Animal?</legend>
  <div class="radio-wrapper">
    <input type="radio" name="animal" id="elephant" />
    <label for="elephant">Elephant</label>
  </div>
  <div class="radio-wrapper">
    <input type="radio" name="animal" id="monkey" />
    <label for="monkey">Monkey</label>
  </div>
  <div class="radio-wrapper">
    <input type="radio" name="animal" id="cheetah" />
    <label for="cheetah">Cheetah</label>
  </div>
  <div class="radio-wrapper">
    <input type="radio" name="animal" id="giraffe" />
    <label for="giraffe">Giraffe</label>
  </div>
</fieldset>
```

The `fieldset` groups all the radio buttons together logically. The radios inputs are all options to the question in the `legend`. Also, remember to associate those form labels with the radio buttons!

![A Fieldset with the question 'What is your favorite Wild Animal?' with four options: Elephant, Monkey, Cheetah, Giraffe.](https://thepracticaldev.s3.amazonaws.com/i/uuwpu368vuu876tdhulq.png)

I'm going to add some straightforward CSS to clean it up a bit.

```scss
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');

* {
  font-family: 'Roboto', sans-serif;
}

fieldset {
  border: none;
}
```

I didn’t do anything much here; I added a font and took away the border from the `fieldset`.

![The fieldset with a sans serif font and no outline on the fieldset](https://thepracticaldev.s3.amazonaws.com/i/z8nqescfb1mkwase27n6.png)

Now let's get to the fun part! Styling these radio buttons!

## Creating a pseudo-element on the label

First thing I am going to do is add a `::before` pseudo-element on the `label` element. I'm going to start with something basic first.

```scss
$muted-red: #db3846;

input[type='radio'] {
  + label {
    position: relative;
    cursor: pointer;
    margin-left: 20px; /* This will be adjusted */

    &::before {
      content: '';
      position: absolute;
      left: -22px; /* This will be adjusted */
      width: 20px;
      height: 20px;
      background: $muted-red;
    }
  }
}
```

The radio buttons won't look like anything much right now. We only want to see the radio buttons to ensure we are replicating the HTML functionality.

![Radio buttons with a red box between the label and the button.](https://thepracticaldev.s3.amazonaws.com/i/aov9cx78mznxtddkhr4x.png)

I'm going to add a teensy amount of margin on the `.radio-wrapper`.

```diff
$muted-red: #db3846;

+ .radio-wrapper {
+ margin: 0.5rem 0;
+ }

input[type='radio'] {
  + label {
    position: relative;
    cursor: pointer;
    margin-left: 20px; /* This will be adjusted */

    &::before {
      content: '';
      position: absolute;
      left: -24px; /* This will be adjusted */
      width: 18px;
      height: 18px;
      background: $muted-red;
    }
  }
}
```

![Radio buttons with a red box between the label and the button, with extra space below each field.](https://thepracticaldev.s3.amazonaws.com/i/dixzy83mlspcdju5kdy6.png)

Now let's remove that background color and round out the edges.

```diff
input[type='radio'] {
  + label {
    position: relative;
    cursor: pointer;
    margin-left: 20px; /* This will be adjusted */

    &::before {
      content: '';
      position: absolute;
      left: -24px; /* This will be adjusted */
+     border-radius: 50%;
+     border: 1px solid #6f686a;
      width: 18px;
      height: 18px;
+     background: transparent;
    }
  }
}
```

As a note, I am going to leave the standard radio buttons for debugging purposes.

![Radio buttons with a large circle between the labels.](https://thepracticaldev.s3.amazonaws.com/i/n3b1i0r48fmtm5gp8ni4.png)

## Add `:checked` styling in CSS

If you've read my post on [keyboard accessible checkboxes](https://www.a11ywithlindsey.com/blog/create-custom-keyboard-accesible-checkboxes) you know about the `:checked` pseudo-class. First, we need to put add an `::after` pseudo-element on the label.

```diff
input[type='radio'] {
  + label {
    position: relative;
    cursor: pointer;
    margin-left: 20px; /* This will be adjusted */

    &::before {
      content: '';
      position: absolute;
      left: -24px; /* This will be adjusted */
      border-radius: 50%;
      border: 1px solid #6f686a;
      width: 18px;
      height: 18px;
      background: transparent;
    }

+   &::after {
+     content: '';
+     position: absolute;
+     left: -20px;
+     top: 4px;
+     border-radius: 50%;
+     width: 12px;
+     height: 12px;
+     background: $muted-red;
+   }
  }
}
```

Now, this is what that looks like:

![Radio buttons with an outlined red circle between the labels.](https://thepracticaldev.s3.amazonaws.com/i/qmmubk8irp7jw2upgoz6.png)

Now we have the styling in place. Let's only add the `background` of the `::after` pseudo-element when the radio input is `:checked`.

```diff
input[type='radio'] {
  + label {
    &::after {
      content: '';
      position: absolute;
      left: -20px;
      top: 4px;
      border-radius: 50%;
      width: 12px;
      height: 12px;
    }
  }

+ &:checked {
+   + label::after {
+     background: $muted-red;
+   }
+ }
}
```

So now if I select a radio button, it'll have a background color!

![A selected radio button with an outlined red circle, indicating it is selected.](https://thepracticaldev.s3.amazonaws.com/i/9877l0h9wgsp1lgzbrt5.png)

If you notice, though, there is no focus styling. Let's focus on that next (see what I did there)

## Add focus styling

If I were to hide the radio button, you would have no idea if I focused on it.

![A focused radio button with an outlined circle.](https://thepracticaldev.s3.amazonaws.com/i/3kumy7cckffepf4m7uer.png)

```scss
input[type='radio'] {
  &:focus {
    + label::before {
      box-shadow: 0 0px 8px $muted-red;
    }
  }
}
```

I decided to add a similar muted red for the focus styling.

![A focused radio button with an outlined red circle.](https://thepracticaldev.s3.amazonaws.com/i/1uzppohknmlmykut8adz.png)

To finish up, I will:

- remove the `opacity` from the radio button itself (the input)
- remove the `margin-left` from the label!

```scss
input[type='radio'] {
  opacity: 0;

  + label {
    position: relative;
    cursor: pointer;
  }
}
```

And Voilà!

![Gif going through custom radio buttons.](https://media.giphy.com/media/RgzwLbAOB4W4aSUkog/giphy.gif)

## Conclusion

When we make custom radio buttons, we have to make sure we account for the following:

1. Creating proper HTML structure with associated form labels!
1. Using pseudo-elements to create the custom-styled element
1. Accounting for the `:checked` pseudo-class
1. Ensuring you can focus on the new radio button
1. Use `opacity: 0` to hide the radio button

If you want to play around with it, here is the finished CodePen!

{% codepen https://codepen.io/littlekope0903/pen/jjgRPL/ %}

Stay in touch! If you liked this article:

- Let me know on [Twitter](https://twitter.com/LittleKope) and share this article with your friends! Also, feel free to tweet me any follow up questions or thoughts.
- Support me on [patreon](https://www.patreon.com/a11ywithlindsey)! If you like my work, consider making a $1 monthly pledge. You’ll be able to vote on future blog posts if you make a \$5 pledge or higher! I also do a monthly Ask Me Anything Session for all Patrons!
- [Be the first to learn about my posts](https://pages.convertkit.com/4218bd5fb5/68dc4e412a) for more accessibility funsies!

Cheers! Have a great week!