Quick Fix · ARIA · Life Hacks

What Does Your Star Rating Widget Actually Say to a Screen Reader?

Illustration of five star icons in a row, with a small speech-bubble showing '4.5 out of 5' beside them, in an oxblood and cream editorial style
  • Quick Fix
  • ARIA
  • Life Hacks

Try this one on your own product page. Turn on a screen reader, tab or arrow your way down to the star rating under a product title, and listen for what gets announced. On a lot of sites, the answer is nothing. Not "4.5 out of 5 stars," not "rating," not even "image" — total silence, as if the widget doesn't exist. Five little SVG or icon-font stars that carry real information for every sighted visitor are, to a screen reader user, a gap in the page.

This is a genuinely common bug, and the good news is it has two clean, well-documented fixes depending on what kind of star widget you're dealing with. A read-only "4.5 stars from 200 reviews" display needs one treatment. An interactive "leave your rating" input needs another. Mixing them up — or skipping both — is how you end up with a rating system half your visitors can see and none of your screen reader users can.

The Stat: WCAG SC 1.1.1 Non-text Content (Level A) requires that a purely visual star-rating graphic have a text alternative conveying the same information — such as "4.5 out of 5 stars" — or it is invisible to a screen reader. (Source: W3C Web Content Accessibility Guidelines)

Silent versus announced star rating widget Two panels. The left panel, labeled SILENT, shows five star shapes with no text label and a crossed-out sound-wave icon, representing a screen reader announcing nothing. The right panel, labeled ANNOUNCED, shows the same five stars next to the text "4.5 out of 5 stars" and an active sound-wave icon, representing a screen reader announcing the rating aloud. SILENT

announced as: (nothing)

ANNOUNCED

announced as: "4.5 out of 5 stars"

Why the stars go silent

Most star widgets are built from one of two ingredients: a row of SVG icons, or a row of icon-font glyphs (think a <span class="icon-star icon-star-filled"> repeated five times). Both are visual-only by default. An SVG with no role, no title, and no accessible name is either ignored outright or, worse, announced as a meaningless "image, image, image, image, image" — five separate unlabeled graphics with no indication of what they collectively mean. An icon font is even quieter: it's just a styled character or a background image, and unless something explicitly labels it, assistive tech has nothing to read.

Visually, the widget is doing its job. A sighted shopper glances at four and a half filled stars out of five and instantly understands the product is well-reviewed. Nothing about that glance requires reading a number — the shape of "mostly full row of stars" carries the meaning on its own. That's exactly the problem SC 1.1.1 Non-text Content exists to catch: information conveyed purely through a visual graphic needs an equivalent text alternative, because a graphic by itself isn't accessible to someone who can't see it.

The fix depends on whether your stars are something a user reads or something a user sets.

Case 1: the read-only display rating

This is the "4.5 out of 5 stars, 200 reviews" widget under a product title or review summary — informational, not interactive. Nobody clicks on it; it just reports a value within a fixed range. That's precisely the shape of the ARIA Authoring Practices Guide's Meter pattern, which is documented for exactly this: a read-only numeric value inside a known minimum and maximum.

A minimal, correct implementation looks like this:

<div role="img" aria-label="Rated 4.5 out of 5 stars">
  <svg aria-hidden="true">...five star shapes...</svg>
</div>

Or, using the more semantically precise meter role when the surrounding markup supports it:

<div role="meter" aria-valuenow="4.5" aria-valuemin="0" aria-valuemax="5"
     aria-label="Product rating: 4.5 out of 5 stars">
  <svg aria-hidden="true">...five star shapes...</svg>
</div>

Either pattern works for SC 1.1.1 as long as the announced text states the actual value in plain language. The critical move in both versions is aria-hidden="true" on the decorative SVG itself — the visual stars stay on screen for sighted users, but a screen reader skips straight past the graphic and reads only the label that describes what the graphic shows.

Case 2: the interactive rating input

A "leave your review" widget is a different animal entirely — it's a form control, not a display. A user needs to know there are five selectable options, which one (if any) is currently selected, and be able to move between them with a keyboard. That's a mutually-exclusive selection from a fixed set, which is exactly what the ARIA Authoring Practices Guide's Radio Group pattern is built for.

In practice, that means treating each star as a radio option inside a labeled group, not as five independent buttons or, worse, five <div>s with click handlers and no role at all:

<div role="radiogroup" aria-label="Rate this product">
  <button role="radio" aria-checked="false" aria-label="1 star">★</button>
  <button role="radio" aria-checked="false" aria-label="2 stars">★★</button>
  <button role="radio" aria-checked="false" aria-label="3 stars">★★★</button>
  <button role="radio" aria-checked="true"  aria-label="4 stars">★★★★</button>
  <button role="radio" aria-checked="false" aria-label="5 stars">★★★★★</button>
</div>

Following the full Radio Group pattern also means arrow-key navigation moves focus between the five options, only the checked option (or the first, if none is checked yet) sits in the tab order, and aria-checked updates the moment a user picks a value — not just visually, but in the accessibility tree too.

Three mistakes that sneak in even after you know the fix

Once a team knows to add labels, a few subtler mistakes tend to show up in their place.

Announcing the fraction instead of the meaning. aria-label="4.5 stars" is fine, but aria-label="90%" on a rating widget forces a screen reader user to do math a sighted user never has to do — nobody looks at a row of stars and thinks "90 percent." Keep the announced text in the same units your sighted users see: stars out of a maximum, not a converted percentage.

Labeling the row but not the count. "4.5 out of 5 stars" is a good label for the rating itself, but if there's a review count next to it ("(200 reviews)"), that count is often a separate visual element with no text alternative of its own — or worse, it's the only accessible content, while the star value silently drops out. Both pieces of information need to reach a screen reader, ideally in one combined label like "Rated 4.5 out of 5 stars, based on 200 reviews," so nothing gets lost between the two visual elements.

Building the interactive version out of five unrelated buttons. A rating input made of five separate <button> elements with no radiogroup wrapper technically has accessible names on each star, but a screen reader user tabbing through them hears five disconnected buttons with no sense that they're mutually exclusive options in a single control, and no arrow-key shortcut between them. The wrapping radiogroup role, plus a group-level label like "Rate this product," is what turns five buttons into one coherent control — matching what a sighted user actually experiences as a single five-point scale, not five independent switches.

A quick checklist for either case

  • Decide first: is this widget read-only display, or a selectable input? The two need different roles — don't reuse one pattern for both.
  • For display ratings, hide the decorative graphic with aria-hidden="true" and put the real value ("4.5 out of 5 stars") in an aria-label or visible text.
  • For input ratings, structure the five options as a labeled radiogroup per the ARIA Authoring Practices Guide's Radio Group pattern, with working arrow-key navigation.
  • Never rely on color or fill percentage alone — a half-filled star needs to resolve to a spoken number, not just a visual fraction.
  • Test both versions with an actual screen reader after shipping; a role that's technically present but mis-wired is easy to miss in a code review.
Widget type Correct pattern What gets announced
Read-only display (e.g., product summary) role="img" label or role="meter" "Rated 4.5 out of 5 stars"
Interactive input (e.g., leave a review) role="radiogroup" of radio options "Rate this product, 4 stars, radio button, checked, 4 of 5"
Neither (unlabeled SVG or icon font) Nothing, or "image, image, image..."

Getting this right matters for more than compliance box-checking — a shopper deciding between two products by ear needs the rating just as much as a shopper deciding by eye, and a review form that silently refuses to tell a screen reader user which star they just picked is a form some percentage of visitors will simply abandon.

If you've never actually listened to your own rating widget with a screen reader, it's worth five minutes today — and if you'd rather have a systematic pass instead of spot-checking page by page, you can find silent widgets on your own site with a free scan and get a concrete list of what to fix first. For the deeper spec language behind all of this, WCAG 1.1.1 Non-text Content is the reference worth bookmarking.