A SaaS pricing page should let a visitor compare plans, choose one with a keyboard, and submit the choice through a normal form. Use native radio buttons inside a fieldset, keep visible labels, and treat the styled pricing cards as an enhancement of that form.
This gives you browser behavior, keyboard support, and a value that can be validated on the server without rebuilding a selection control from generic div elements.
Each plan is one option in a single choice. That maps directly to radio buttons that share the same name.
MDN recommends grouping a set of radio buttons with fieldset; the nested legend gives the group a caption. The shared name="plan" also means the browser submits one selected value.
Wrapping the radio input inside its label makes the whole card part of the control. A visitor can click the text, price, or empty space inside the label.
Keep the input available to assistive technology. Do not use display: none on it. You can place it visually and style the card from its state.
Do not make color the only selected-state signal. Keep the radio control visible, add a border change, and make the keyboard focus easy to see.
If you need to support browsers without :has(), add a small progressive enhancement that toggles a class. The radio buttons should still work without it.
Each card should answer: What does it cost, including the billing period? Who is it for? What limit changes between plans? Which important feature is included or excluded? What happens after the visitor continues?
Use the same order for each card. Avoid putting the critical difference in a tooltip. Tooltips are easy to miss on touch screens and during keyboard use.
If monthly and annual billing change the displayed price, keep the billing period in the visible text and in the submitted data. A number without its period can create a false comparison.
You may want the button to repeat the selected plan. Read the checked radio instead of creating a second source of truth.
The form remains usable if this script fails. JavaScript changes the feedback, while HTML keeps the selection and submission working.
Look up the current price and entitlements on the server. Do not accept a price from a hidden field or query string. A visitor can edit client-side values before submitting the form.
Before saving the page, test these cases: Tab to the selected option and move through the group with arrow keys. Zoom the page and confirm the cards reflow without hiding content. Click every part of each card. Submit each plan and confirm the server receives the expected value. Disable JavaScript and confirm selection and submission still work. Use a screen reader to check that the group legend and plan labels are announced clearly.
A pricing page is a decision form. Native controls give that decision a reliable base, while the visual cards help people compare the options.
Hey I'm Uriel Bitton. I write about building in public strategies and growing startups.
Sources MDN: The fieldset element MDN: How to structure a web form MDN: Radio input
