Open any group, copy the HTML into your form and the CSS into your stylesheet. Every option is a real <input type="radio"> inside its <label>, and the group shares one name, so arrow keys move the selection and the form submits the chosen value.
Give each group on a page its own name. To change the color, set --rad-color; to change the size, set --rad-size. Sliding indicators and dots follow the checked input with :checked and sibling or :has() selectors.
Every snippet keeps a visible :focus-visible ring and ships with a prefers-reduced-motion rule that moves the selection instantly for people who asked their OS for less motion.
Set appearance: none on the input, give it a size and border-radius: 50%, then draw the inner dot with a ::before or a radial-gradient that appears on :checked.
Draw the dot yourself with a pseudo-element or radial gradient on :checked, or use accent-color on native radios. On every snippet here, --rad-color does it.
Keep the inputs, hide them visually (not with display: none) and style each label as a button. A sliding pill behind the checked label turns the group into a segmented control.
Use five radios in normal 1 to 5 order and light the chosen star and every star before it with label:has(~ label :checked). The older row-reverse trick works visually, but it makes the arrow keys move the rating the wrong way.
Yes, if the real inputs stay in the page, share a name, have labels and keep a visible focus style. Arrow keys then move between options as users expect.