Radio Button

One choice from a group.

Delivery speed

html

<fieldset class="radio-fs radio-fs--md" style="--accent:#BFD9F2;">
  <legend>Delivery speed</legend>
  <label class="radio-opt">
    <input type="radio" name="speed" id="speed-standard" checked>
    <span>Standard</span>
  </label>
  <label class="radio-opt">
    <input type="radio" name="speed" id="speed-express">
    <span>Express</span>
  </label>
</fieldset>
<style>
.radio-fs { border: none; padding: 0; margin: 0; font: 14px system-ui, sans-serif; color: #241430; display: flex; flex-direction: column; gap: 8px; }
.radio-fs legend { font-weight: 500; margin-bottom: 4px; padding: 0; }
.radio-opt { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
.radio-opt input { appearance: none; margin: 0; width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid #24143050; position: relative; flex: none; }
.radio-fs--sm .radio-opt input { width: 15px; height: 15px; }
.radio-fs--lg .radio-opt input { width: 22px; height: 22px; }
.radio-opt input:checked { border-color: var(--accent); }
.radio-opt input:checked::after { content: ""; position: absolute; inset: 3px; border-radius: 50%; background: var(--accent); }
.radio-opt input:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 40%, transparent); }
.radio-opt input:disabled { opacity: .5; cursor: not-allowed; }
</style>

tailwind

<fieldset class="radio-fs-tw radio-fs-tw--md border-0 p-0 m-0 font-sans text-sm text-[#241430] flex flex-col gap-2" style="--accent:#BFD9F2;">
  <legend class="font-medium mb-1 p-0">Delivery speed</legend>
  <label class="inline-flex items-center gap-2 cursor-pointer">
    <input type="radio" name="speed-tw" class="radio-tw appearance-none m-0 w-[18px] h-[18px] rounded-full border-[1.5px] border-[#24143050] relative flex-none disabled:opacity-50 disabled:cursor-not-allowed" checked>
    <span>Standard</span>
  </label>
  <label class="inline-flex items-center gap-2 cursor-pointer">
    <input type="radio" name="speed-tw" class="radio-tw appearance-none m-0 w-[18px] h-[18px] rounded-full border-[1.5px] border-[#24143050] relative flex-none disabled:opacity-50 disabled:cursor-not-allowed">
    <span>Express</span>
  </label>
</fieldset>
<style>
.radio-fs-tw--sm .radio-tw { width: 15px !important; height: 15px !important; }
.radio-fs-tw--lg .radio-tw { width: 22px !important; height: 22px !important; }
.radio-tw:checked { border-color: #BFD9F2 !important; }
.radio-tw:checked::after { content: ""; position: absolute; inset: 3px; border-radius: 50%; background: #BFD9F2; }
.radio-tw:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, #BFD9F2 40%, transparent); }
</style>

react

export function RadioButton({
  label = "Delivery speed",
  selected = false,
  size = "md",
  accent = "#BFD9F2",
  disabled = false,
}) {
  const dim = { sm: 15, md: 18, lg: 22 }[size] ?? 18;
  const dot = (checked) => (
    <span style={{
      appearance: "none", display: "inline-block", width: dim, height: dim, borderRadius: "50%",
      border: `1.5px solid ${checked ? accent : "#24143050"}`, position: "relative", flex: "none",
      opacity: disabled ? 0.5 : 1,
    }}>
      {checked && <span style={{ position: "absolute", inset: 3, borderRadius: "50%", background: accent }} />}
    </span>
  );
  return (
    <fieldset style={{ border: "none", padding: 0, margin: 0, fontFamily: "system-ui, sans-serif", fontSize: 14, color: "#241430", display: "flex", flexDirection: "column", gap: 8 }}>
      <legend style={{ fontWeight: 500, marginBottom: 4, padding: 0 }}>{label}</legend>
      <label style={{ display: "inline-flex", alignItems: "center", gap: 8, cursor: disabled ? "not-allowed" : "pointer" }}>
        {dot(!selected)}
        <span>Standard</span>
      </label>
      <label style={{ display: "inline-flex", alignItems: "center", gap: 8, cursor: disabled ? "not-allowed" : "pointer" }}>
        {dot(selected)}
        <span>Express</span>
      </label>
    </fieldset>
  );
}