Actual CSS

Rating

Integer star rating built from native radio inputs, and a read-only display of a rating.

Each star is a real input[type="radio"], so submission, required, disabled state, form reset, and keyboard navigation remain native. Keep values and DOM order ascending. The cumulative fill and hover preview use :has() as a progressive enhancement; older supported browsers show only the selected star filled while the control remains fully functional.

Class reference

ClassKindDescription
.ratingComponentRadio group presented as stars.
.rating[role="img"]ComponentRead-only display of a value.
.sm / .lgSizeSmaller or larger star geometry.
Rate your experience
<fieldset class="field">
  <legend class="field-label">Rate your experience</legend>
  <div class="rating">
    <input type="radio" name="experience" value="1" aria-label="1 star" />
    <input type="radio" name="experience" value="2" aria-label="2 stars" />
    <input type="radio" name="experience" value="3" aria-label="3 stars" checked />
    <input type="radio" name="experience" value="4" aria-label="4 stars" />
    <input type="radio" name="experience" value="5" aria-label="5 stars" />
  </div>
</fieldset>

Use a visible <legend> to name the group and an aria-label on every radio to name its value. Add required to the radios when the form must receive a rating. In forced-colors mode the stars deliberately return to native platform radios so checked and focus states remain unambiguous.

Intent classes change the active color without changing the interaction model.

Small rating
Large rating
<div class="cluster">
  <fieldset class="field">
    <legend class="field-label">Small rating</legend>
    <div class="rating primary sm">
      <input type="radio" name="small-rating" value="1" aria-label="1 star" />
      <input type="radio" name="small-rating" value="2" aria-label="2 stars" checked />
      <input type="radio" name="small-rating" value="3" aria-label="3 stars" />
    </div>
  </fieldset>

  <fieldset class="field">
    <legend class="field-label">Large rating</legend>
    <div class="rating danger lg">
      <input type="radio" name="large-rating" value="1" aria-label="1 star" />
      <input type="radio" name="large-rating" value="2" aria-label="2 stars" />
      <input type="radio" name="large-rating" value="3" aria-label="3 stars" />
      <input type="radio" name="large-rating" value="4" aria-label="4 stars" checked />
      <input type="radio" name="large-rating" value="5" aria-label="5 stars" />
    </div>
  </fieldset>
</div>

Read-only display

To show a rating rather than collect one (reviews, testimonials, average score, star display), use one element with role="img" and the value in --rating-value. Fractions draw a partial star. The aria-label carries the value; without role="img" nothing is drawn, so a display cannot ship without an accessible name. Do not present a value with disabled radios.

4.5 from 312 reviews

<p>
  <span class="rating" role="img" aria-label="4.5 out of 5 stars" style="--rating-value: 4.5"></span>
  4.5 from 312 reviews
</p>

<span class="rating sm primary" role="img" aria-label="7 out of 10" style="--rating-value: 7; --rating-max: 10"></span>

Stars line up with an input .rating of the same size, and .sm, .lg and intent classes apply as above. The fill follows the writing direction. In forced-colors mode the filled share is painted in system colors.

Hooks

  • --rating-size — size of each star; .sm and .lg set this hook.
  • --rating-gap — visual space between stars without creating inactive hover zones.
  • --rating-color — star color. Prefer an intent class for semantic color.
  • --rating-empty — color of unselected stars; use a surface or border token.
  • --rating-star — mask image used to draw a star; override it when a strict CSP disallows data URLs.
  • --rating-value — display only: the value shown, fractions allowed.
  • --rating-max — display only: the number of stars.
Actual CSS

Search documentation