radio button

Radio buttons can be used to present the user with only one choice out of a list of choices

See Form for example usage in a form.

In order for radio buttons to work correctly, the input tag needs a unique id attribute and the label tag needs the same for attribute. To ensure that only one options is selectable, the mutually-exclusive options need the same name attribute.

component variations

default

<div class="a-radio-button">
  <input type="radio" id="radio-button-1" name="default" value="test" />
  <label for="radio-button-1">Radio Button Label</label>
</div>

disabled unchecked

<div class="a-radio-button">
  <input
    type="radio"
    id="radio-button-2"
    name="disabled unchecked"
    disabled=""
    value="test"
  />
  <label for="radio-button-2">Radio Button Label</label>
</div>

disabled checked

<div class="a-radio-button">
  <input
    type="radio"
    id="radio-button-3"
    name="disabled checked"
    disabled=""
    checked=""
    value="test"
  />
  <label for="radio-button-3">Radio Button Label</label>
</div>

additional content

styles SCSS

/* stylelint-disable no-descending-specificity */
.a-radio-button {
  position: relative;
  display: inline-block;

  input {
    height: 0;
    width: 0;
    opacity: 0; // Hides the input in Safari
    -moz-appearance: none; // Hides the input in Firefox
    outline: none; // Hides the input's native outline

    &:focus {
      outline: hidden;
    }

    // Outline for keyboard navigation
    &:focus-visible + label::before {
      outline: 3px solid var(--plain__enabled__front__default);
      outline-offset: 3px;
    }
    &:focus-visible + label::after {
      outline: 3px solid var(--background);
      outline-offset: 6px;
    }
  }

  label {
    color: var(--plain__enabled__front__default);
    display: inline-block; // Fix for Safari to avoid multiline
    padding-left: 2rem;
    line-height: 1.5;
    font-size: 1rem;
    cursor: pointer;

    &::before {
      position: absolute;
      content: "";
      width: 1.5rem;
      height: 1.5rem;
      background-color: var(--small__enabled__fill__default);
      left: 0;
      top: 0;
      border-radius: 0.75rem;
    }

    &:hover::before,
    &:focus::before {
      background-color: var(--small__enabled__fill__hovered);
    }

    &:active::before {
      background-color: var(--small__enabled__fill__pressed);
    }
  }

  // Input is disabled
  input:disabled ~ label {
    cursor: default;
    color: var(--plain__disabled__front__default);

    &::before {
      background-color: var(--small__disabled__fill__default);
    }
  }

  // Input is checked
  input:checked ~ label {
    &::before {
      background-color: var(--major-accent__enabled__fill__default);
    }

    &::after {
      background-color: var(--major-accent__enabled__front__default);
      border-radius: 50%;
      content: "";
      display: inline-block;
      height: 0.75rem;
      left: 0;
      position: absolute;
      top: 0;
      transform-origin: top left;
      transform: translateX(0.375rem) translateY(0.375rem);
      width: 0.75rem;
    }

    &:hover::before {
      background-color: var(--major-accent__enabled__fill__hovered);
    }

    &:active::before {
      background-color: var(--major-accent__enabled__fill__pressed);
    }
  }

  // Input is checked and disabled
  input:checked:disabled ~ label {
    &::before {
      background-color: var(--major-accent__disabled__fill__default);
    }

    &::after {
      background-color: var(--major-accent__disabled__front__default);
    }
  }
}