Rating Stars

Used to display or enter a feedback rating on a 1 to 5 star scale.

Displaying rating stars

The rating stars pattern is a well-established way of communicating an average user-ratings result. Because the stars are graphical, you must provide a text alternative to the rating content. When displaying the rating stars, we hide the icons from screen readers using an aria-hidden attribute while providing the information as visible text close by.

<div class="display-star-rating">
<div class="display-star-group" aria-hidden="true" role="img" style="width: 5em"><span class="display-star-value" style="width:3em"></span></div>
<p>Average rating: 3 (out of 5)</p>
</div>
.display-star-group {
background-image: url("/static/icons/star-empty.svg");
background-repeat: repeat-x;
display: inline-block;
}
.display-star-group, .display-star-value {
background-size: 1em ;
height: 1em;
}
.display-star-value {
background-image: url("/static/icons/star-filled.svg");
background-repeat: repeat-x;
display: block;
}

Screen reader: "Average rating: 3 (out of 5)"

Customizing display stars

You can adjust the number of possible stars and the number of filled-in stars by modifying the widths of the elements with classnames of display-star-group and display-star-value, respectively. The overall size of the stars will scale with the surrounding font size. You can use CSS filters [1] to change the color of the SVG images that display the stars.

<div class="display-star-rating">
<div class="display-star-group display-star-gold" aria-hidden="true" role="img" style="font-size: 2rem; width: 10em"><span class="display-star-value" style="width: 4.5em"></span></div>
<p>Average rating: 4.5 (out of 10)</p>
</div>

Supporting internationalization

When displaying rating stars in languages that are from read right to left, the order of the stars should follow the same direction the text is written in and appear in right-to-left order. The CSS below will flip and reorder the icons based on the presence of an HTML dir attribute with the value of rtl.

.display-star-rating[dir="rtl"] .display-star-value {
transform: scaleX(-1);
filter: FlipH;
}
<div class="display-star-rating" dir="rtl" lang="ar">
<div class="display-star-group" aria-hidden="true" role="img" style="width: 10em"><span class="display-star-value" style="width: 6.5em"></span></div>
<p>متوسط ​​التصنيف: 6.5 نجوم</p>
</div>

Interactive star rating

Interactive rating stars allow users to enter their feedback on a star scale, for example, rating products on sale. This data helps others make informed decisions and provides organizations with valuable customer sentiment data.

Use web form elements

Although this component appears to be a purely custom element, we built our implementation on a semantically-aligned native HTML element: a group of input elements of type "radio." By starting with a usable HTML foundation, we ensure that the final component will have maximum compatibility with assistive technologies and will continue to be usable when JavaScript is unavailable on the client.

An HTML input element with the type "range" would have also been a semantically appropriate foundation. However, we didn't go in that direction due to incompatibilities [2] that still exist with the new HTML5 input types when interpreted by various browser, device, and assistive technology combinations and because of the potential difficulties some disabled users have with elements that require a slider-type interaction.

Some users of touch-based assistive technologies may experience difficulty utilizing widgets that implement this slider pattern because the gestures their assistive technology provides for operating sliders may not yet generate the necessary output. To change the slider value, touch-based assistive technologies need to respond to user gestures to increase and decrease the value by synthesizing key events. This is a new convention that some assistive technologies may not fully implement. [3]

Avoid background images

Implementations that utilize background images to display any input star states are inaccessible for users who rely on a high-contrast rendering mode. [4] When this mode is activated (either at the system or browser level), web elements will no longer display any background images. This is similar to the view you may have seen when printing a webpage.

The primary issue with non-decorative CSS background images is that when images are turned off or when high contrast mode is enabled (for example, under the Windows OS), background images disappear. If the background image either contains text ... or provides meaningful icon imagery, then users of high contrast mode and those without images will not see that content. [5]

In the case of the ratings star component, the problem for sighted users would be that under high contrast mode, the label text would still be hidden, but if the icons were implemented as background images, they too would become hidden.

Touch target size

The W3C recommends a minimum target size of 44px x 44px for interactive elements to ensure users can activate them accurately. [6] This requirement is specifically helpful for touchscreen users and people with motor control difficulties. Ensure there is enough room, for example, to allow a user on a bus, holding a phone with one hand, to press the rating they wish to accurately.

Example implementation

[data-ddp-component-ratingstars] > .star-group {
display: inline-flex;
}
[data-ddp-component-ratingstars] input[type="radio"] {
/* visually hidden radiobutton inputs */
clip-path: inset(50%);
height: 1px;
left: -9999px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
[data-ddp-component-ratingstars] input[type="radio"] + label {
/* visually hidden text */
color: transparent;
cursor: pointer;
font-size: 0;
min-width: 2.8rem;
}
[data-ddp-component-ratingstars] input[type="radio"]:focus:not(:focus-visible) + label {
border-bottom: inherit;
}
[data-ddp-component-ratingstars] input[type="radio"]:focus-visible + label {
/* focus indicator but only when focused by keyboard */
border-bottom: 4px solid goldenrod;
}
[data-ddp-component-ratingstars] input[type="radio"]:checked ~ label:after,
[data-ddp-component-ratingstars]:not([data-star-value]) input[type="radio"] + label:after
{
content: url("/static/icons/star-empty.svg");
content: url("/static/icons/star-empty.svg") / "";
}
[data-ddp-component-ratingstars] input[type="radio"]:checked + label:after,
[data-ddp-component-ratingstars] input[type="radio"] + label:after
{
content: url("/static/icons/star-filled.svg");
content: url("/static/icons/star-filled.svg") / "";
}
document.addEventListener('DOMContentLoaded', (ev) => {
document.querySelectorAll('.star-rating').forEach(el => el.setAttribute('data-ddp-component-ratingstars', ''));
document.querySelectorAll('.star-group input[type="radio"]').forEach(el => el.addEventListener(
'change', ev => {
const { target } = ev;
target.closest('.star-rating').setAttribute('data-star-value', target.value);
})
);
});
<fieldset class="star-rating">
<legend>Your rating:</legend>
<div class="star-group">
<input type="radio" name="rating" value="1" id="rating1">
<label for="rating1">1 star</label>
<input type="radio" name="rating" value="2" id="rating2">
<label for="rating2">2 stars</label>
<input type="radio" name="rating" value="3" id="rating3">
<label for="rating3">3 stars</label>
<input type="radio" name="rating" value="4" id="rating4">
<label for="rating4">4 stars</label>
<input type="radio" name="rating" value="5" id="rating5">
<label for="rating5">5 stars</label>
</div>
<p>Average rating: 4.6</p>
</fieldset>

Screen reader: "1 star, radio button, 1 of 5, Your rating:, group"
Screen reader: "selected, 1 star, radio button, 1 of 5"
Screen reader: "2 stars, selected, radio button, 2 of 5"

Supporting internationalization

The text used to label each star, which while not visible, will be announced by screen readers, is in the content of the HTML label element rather than as an HTML attribute value. This means it can be translated by browser extensions and services such as Google Translate.

By applying the dir attribute with a value of rtl (right to left), the component automatically uses a layout natural to those languages.

<fieldset class="star-rating" dir="rtl" lang="ar">
...
</fieldset>

Checkpoints for the Tester

  1. Activate high contrast mode rendering [7] (removing background images and applying a forced color mode of a black foreground on a white background). Confirm that the star icons are all visible and indicate a filled or empty state. For interactive rating, ensure that the focus indicator is visible and shows which star currently has focus when navigating by keyboard.
  2. Using only the keyboard, ensure that it is possible to use the tab key to move focus into the interactive rating star group and that it is possible to select the focused star using the space key. By using the arrow keys, ensure that changing the focused / selected star is possible. For interactive rating, ensure that focus indication is visible when navigating by keyboard and shows which star currently has focus.
  3. Enable automatic dark mode rendering [8] (applying a forced color mode of a light foreground on dark background). Confirm that the star icons are all visible and indicate a filled or empty state. While in dark mode, ensure that focus indication is visible when navigating by keyboard and shows which star currently has focus.
  4. Using a screen reader, move focus into the interactive rating star group. Ensure that the screen reader announces that the items are "stars," which number star currently has focus, if the currently focused star is selected or unselected, and what the total number of stars is.
  5. With JavaScript disabled, ensure it is possible to see the star rating value. For interactive rating, ensure it is possible to enter and submit a rating.
  6. For interactive rating, ensure that the touch target area of each star is no smaller than 44 by 44 CSS pixels at all supported screen sizes.
  7. With the text size enlarged to 200% of its default size, ensure that the touch target area scales in relation to the surrounding text. Ensure that the star icons cover the entire touch target area for interactive rating.
  8. Ensure that the focus indication and the filled-in status of each star do not depend solely on a color difference and that the contrast of the indication is sufficient.

Notes and references

  1. filter, mdn web docs back to reference 1

  2. We still can't use the HTML range input, either, James Catt back to reference 2

  3. w3C Aria Practices back to reference 3

  4. "In WebAIM's 2018 low vision survey, 30.6% of respondents used a high contrast mode." assistivlabs "High Contrast Mode" back to reference 4

  5. CSS Background Images and Accessibility, Level Access back to reference 5

  6. WCAG 2.1 Understanding Docs, Target Size (Level AAA) back to reference 6

  7. Versions of the Chrome (and Edge browsers) later than 98 allow you to set forced-colors to "active" in the "Rendering" pane of DevTools. back to reference 7

  8. Auto Dark Theme, Chrome Developer's Blog back to reference 8