Skip to content

Radio Card Selector

Tailwind CSS plan picker that turns native radio inputs into selectable pricing cards with a check indicator, focus ring and live summary.

Live preview

Open in new tab

Code

A plan selector built with Tailwind CSS where each option is a native radio input styled as a large card with price, features and a check indicator. It is a common step in sign-up, checkout and onboarding flows, and works as a regular form field even without JavaScript.

How it works

The root is .trc-plans, which contains a form marked data-trc-form and a fieldset whose legend holds the step label, heading and intro text. Each plan is a label with the group class wrapping a visually hidden input type="radio" name="plan" (sr-only). Because the input sits inside the label, clicking anywhere on the card selects it, and the browser handles arrow-key movement between the three options.

All visual states come from Tailwind v4 has-* variants, so no JavaScript is needed for styling: has-[:checked]:border-emerald-600 and has-[:checked]:bg-emerald-50/60 highlight the selected card, group-has-[:checked]:bg-emerald-600 fills the round indicator and group-has-[:checked]:opacity-100 reveals its check mark. has-[:focus-visible]:outline-2 draws a focus ring around the whole card when the radio is focused with the keyboard. The middle card starts checked and shows a "Most popular" badge.

script.js initializes every .trc-plans on DOMContentLoaded. A change listener on each radio writes the plan name and price, read from data-trc-name and data-trc-price, into data-trc-summary in the dark footer bar. Submitting the form disables data-trc-submit, shows "Saving your plan…" in the data-trc-status region and simulates a request with setTimeout. style.css only adds a subtle press effect on :active.

Customization

  • data-trc-name and data-trc-price on each radio: change the text shown in the summary bar.
  • value on each radio (starter, team, business): set the values your backend expects for the plan field.
  • Move the checked attribute to another radio to change the default plan, and move the #trc-team-badge span to highlight a different card.
  • emerald utilities (has-[:checked]:border-emerald-600, group-has-[:checked]:bg-emerald-600, bg-emerald-500 on the button): replace with violet or blue to rebrand.
  • md:grid-cols-3 on the card grid: use md:grid-cols-2 for two plans or add lg:grid-cols-4 for four.
  • rounded-3xl and border-2 on each label: use rounded-xl and border for a tighter, more compact look.
  • Replace the setTimeout in the submit handler of script.js with a fetch() call to your billing endpoint.

Accessibility

The options are real radio buttons grouped by a fieldset and legend, so screen readers announce the group name, the number of options and the current choice. Each radio gets a short accessible name through aria-labelledby (plan name and price) and its description through aria-describedby, instead of reading the whole card. Arrow keys move between plans, Space selects, and the card shows a clear outline on keyboard focus. The selected state is shown by border, background and a check icon, not by color alone. Decorative icons are aria-hidden, form feedback uses role="status", and transitions are disabled with motion-reduce:transition-none.

Usage notes

For several selectors on one page, give each group a different name and unique id values.

Requirements

Add these to your page (already included in the download):

  • <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

The Tailwind browser build is for prototyping. In production, compile Tailwind with its CLI or your bundler.

Radio Card Selector – Tailwind CSS checkboxes & radios component screenshot
Radio Card Selector · Tailwind CSS Checkboxes & Radios

More Checkboxes & Radios

Custom Checkboxes and Switches – Bootstrap 5 checkboxes & radios preview

Custom Checkboxes and Switches

Restyled Bootstrap 5 checkboxes, large switches, select-all with indeterminate state, radio cards and colored checkbox chips.