Bryntum
12 February 2026

Three ways to style radio buttons with CSS in 2026

Styling native radio buttons across browsers has always been more of a headache than it should be. Even in 2026, […]

Styling native radio buttons across browsers has always been more of a headache than it should be. Even in 2026, the go-to approach is still to use appearance: none to strip the native look before restyling the radio button. The good news is that browser support for restyling techniques has improved since we first published this article in 2022.

Quick HTML setup first

Every radio input needs a label for accessibility. The simplest way without using the for attribute and setting ids is to wrap the input inside a <label> element.

Use the same name attribute on each input, so only one radio button can be selected at a time:

<label class="radio-label">
  <input type="radio" name="demo" />
  Option A
</label>

<label class="radio-label">
  <input type="radio" name="demo" checked />
  Option B
</label>

Three ways to style radio buttons

With improved browser support for modern CSS, we can style radio buttons more easily. Let’s look at the three options used in the CodePen:

See the Pen 3 ways to style radio buttons by Bryntum (@bryntum-snippets) on CodePen.

Using accent-color

This is the simplest option. The accent-color property colors the button with a single line of CSS. It’s supported in Chrome, Edge, and Firefox, but has limited support in Safari.

.radio-label input[type="radio"] {
  accent-color: #FF5722;
}

You keep all default browser behavior, accessibility, and focus styles, but it only changes the color.

Using box-shadow

Using box-shadow doesn’t risk affecting the layout of other elements (like using border), and it works in all modern browsers. But first, hide the radio button with appearance: none. Use a white border as spacing between the dot and the outer ring in addition to using box-shadow for the ring itself.

Here’s the box-shadow solution:

  /* Hide native radio and restyle */                                                                                    
  input[type="radio"] {
    appearance: none;                                                                                                    
    width: 1.15em;                                          
    height: 1.15em;
    border-radius: 50%;

    /* White border = spacing between dot and ring */
    border: 0.15em solid #FFF;

    /* box-shadow for the outer ring */
    box-shadow: 0 0 0 0.1em #999;

    /* Center the ::before dot */
    display: grid;
    place-content: center;
  }

  /* Smooth animation: dot scales in via ::before */
  input[type="radio"]::before {
    content: "";
    width: 0.8em;
    height: 0.8em;
    border-radius: 50%;
    transform: scale(0);
    transition: 120ms transform ease-in-out;

    /* Printer-friendly: box-shadow inset instead of background-color */
    box-shadow: inset 1em 1em #FF5722;
  }

  /* Keyboard accessible: focus ring on tab, not on click */
  input[type="radio"]:focus-visible {
    outline: max(2px, 0.1em) solid currentColor;
    outline-offset: max(2px, 0.1em);
  }

The fix includes some extras, which we’ll also apply to the outline solution in the next section:

Using outline

The outline solution uses the same technique as the box-shadow solution above, but creates the outer circle using the outline property instead.

When we first published this article in 2022, outlines didn’t work well with border-radius in Safari. That long-standing bug was fixed in Safari 16.4, making outline the best option for styling radio buttons.

Here’s the complete outline solution with the same smooth animation, printer-ready, keyboard accessible, and font-scalable additions:

/* Hide native radio and restyle */
.radio-label input[type="radio"] {
    appearance: none;
    margin: 0;
    width: 1.15em;
    height: 1.15em;
    border-radius: 50%;

    /* White border gap between dot and ring */
    border: 0.15em solid #FFF;

    /* Outline for the ring */
    outline: 0.1em solid #999;

    /* Pull the ring so it sits against the border */
    outline-offset: -0.05em;

    /* Center the dot */
    display: grid;
    place-content: center;
}

/* Smooth animation with scale and transform */
.radio-label input[type="radio"]::before {
    content: "";
    width: 0.8em;
    height: 0.8em;
    border-radius: 50%;
    transform: scale(0);
    transition: 120ms transform ease-in-out;

    /* Printer-friendly: box-shadow inset instead of background-color */
    box-shadow: inset 1em 1em #FF5722;
}

/* Keyboard accessible: since outline is taken, box-shadow handles the focus */
.radio-label input[type="radio"]:focus-visible {
    outline-color: currentColor;
    box-shadow: 0 0 0 max(2px, 0.1em) currentColor;
}

Themes with currentColor

You can color a whole group at once with currentColor:

.radio-label {
  color: rebeccapurple;
}

.radio-label input[type="radio"] {
  outline: 0.1em solid currentColor;
}

.radio-label input[type="radio"]::before {
  box-shadow: inset 1em 1em currentColor;
}

Accessible reminders

Use :focus-visible for a keyboard focus ring. It’s not good accessibility practice to interfere with focus styles without an alternative.

Use appearance: none to hide the radio button. Never use display: none because it removes the radio button from the accessibility tree.

Plans for native styling

The Open UI initiative has plans to make all form controls natively styleable. Their first result shipped in late 2024: customizable <select> elements in Chrome.

Which one should you use?

Now that Safari supports outlines following border-radius, the outline approach is the best default choice. It’s customizable and doesn’t affect the layout.

The box-shadow approach is good if you want to keep the default focus.

If you just need a quick color change use the one-line accent-color approach.

At Bryntum, we use the box-shadow technique in our Radio button widget for its historically reliable cross-browser appearance. You can see it in action in the Scheduler Pro Event Editor dialog.

Bryntum

Design Tips 'n tricks