7 Pure CSS1 with JSPublished 2026-10-04Free · no sign-up
Eight radio button designs for real interfaces: a plain custom radio, plan cards, a segmented control, colour swatches, clothing sizes, payment methods, a settings list and shipping options. Each group sits in a fieldset with a legend, so the question is read together with the choices.
Native radio inputs restyled with appearance: none. The inner dot is an inset box-shadow, so it scales cleanly at any zoom level, and the group sits in a fieldset with a legend so the question is announced together with the choices.
View code
<fieldset class="rad">
<legend>Delivery</legend>
<label><input type="radio" name="d" checked> Standard (3 to 5 days)</label>
<label><input type="radio" name="d"> Express (next day)</label>
<label><input type="radio" name="d"> Collect in store</label>
</fieldset>
Radio buttons presented as plan cards with a name, a price and a short line of detail. The whole card is clickable, the selected card is outlined using :has(), and the arrow keys still move between plans because the inputs share one name.
A segmented control for switching views, like List, Grid and Map. The radios are hidden but still focusable, the selected segment is raised with a white background and shadow, and a fieldset keeps the group semantics for assistive technology.
The colour picker from a product page. Each swatch is a radio with an accessible colour name, the chosen swatch gets a double ring drawn with box-shadow, and the selected colour name is echoed above the swatches with a small script.
Clothing sizes as square pills, including a sold-out size that is disabled and crossed through. Disabled radios are skipped by the keyboard automatically, and the sold-out state is spelled out in hidden text rather than shown only with a line.
A checkout step listing card, bank transfer and cash on delivery. Each option is a row with an icon tile and a hint, and the extra hint text only appears for the selected method, keeping the step short until a choice is made.
View code
<fieldset class="pay">
<legend>Payment method</legend>
<label class="opt"><input type="radio" name="pay" checked><span class="ic">CARD</span><span><b>Credit or debit card</b><small>Visa, Mastercard and Amex accepted.</small></span></label>
<label class="opt"><input type="radio" name="pay"><span class="ic">BANK</span><span><b>Bank transfer</b><small>We email the account details after you order.</small></span></label>
<label class="opt"><input type="radio" name="pay"><span class="ic">COD</span><span><b>Cash on delivery</b><small>Pay the courier when your parcel arrives.</small></span></label>
</fieldset>
A settings-style radio list with a title and an explanation for each choice, separated by thin rules. The description is part of the label, so clicking anywhere on the row selects it, and the selected row is marked with a coloured bar on the left edge.
View code
<fieldset class="vis">
<legend>Profile visibility</legend>
<label><input type="radio" name="vis" checked><span><b>Public</b><em>Anyone can see your shop and reviews.</em></span></label>
<label><input type="radio" name="vis"><span><b>Customers only</b><em>Only people who bought from you.</em></span></label>
<label><input type="radio" name="vis"><span><b>Private</b><em>Hidden from everyone but you.</em></span></label>
</fieldset>
Shipping choices with a delivery estimate on the left and the price on the right, the way checkouts usually show them. The free option is highlighted with a badge, and prices are kept in a separate column so they line up for easy comparison.
Radio buttons only make sense as a group. Put them in a <fieldset> with a <legend> that asks the question, and give every input the same name. Screen readers then announce the question with each option, and the arrow keys move between options automatically.
Hidden but focusable
For swatches, sizes and segmented controls the circle is hidden and the label is styled instead. Hide the input with opacity or a visually-hidden class, never with display: none, so it can still receive focus. Then style input:focus-visible + label so keyboard users can see where they are.
Showing the selection
The selected option needs a cue beyond colour: a thicker border, a filled background, a tick or a left bar. The plan cards and settings list use :has(input:checked) on the label; the swatches use a double ring drawn with two box-shadows.
Disabled options
A sold-out size should be disabled so it cannot be chosen, and the reason should be in text, such as a visually hidden (sold out). Disabled radios are skipped by the keyboard, and a diagonal line gives a visual hint.
Frequently asked questions
Can a radio group have no selection?
Yes until the person picks one, but once chosen it cannot be cleared. Pre-select a sensible default where one exists.
Should I use radios or a select menu?
Radios are better for up to about six options because every choice is visible at once.
Do these need JavaScript?
No, except the swatch demo, which echoes the chosen colour name.