Skip to content
ShineUI
Install

Rating

Stars for feedback moments.

<sui-rating>Advanced inputsStable

About

Star rating for feedback moments such as a post-support survey or a CSAT prompt. Orange stars fill on hover as a preview, and picking the selected star again clears the rating. Not for financial data, where a number belongs in a field.

Usage

<sui-rating label="How was reconciliation?" name="csat" value="4" show-count help="Feedback goes to the support team."></sui-rating> <script type="module"> import { defineCustomElements } from "@shineui/core/loader"; import "@shineui/core/shineui.css"; defineCustomElements(); const el = document.querySelector("sui-rating"); el.addEventListener("suiChange", (e) => console.log(e.detail)); </script>
import { SuiRating } from "@shineui/react"; import "@shineui/core/shineui.css"; export function Example() { return <SuiRating label="How was reconciliation?" name="csat" value="4" showCount help="Feedback goes to the support team." onSuiChange={(e) => console.log(e.detail)} />; }
<script setup> import { SuiRating } from "@shineui/vue"; import "@shineui/core/shineui.css"; const onChange = (e) => console.log(e.detail); </script> <template> <SuiRating label="How was reconciliation?" name="csat" value="4" show-count help="Feedback goes to the support team." @sui-change="onChange" /> </template>
import { Component } from "@angular/core"; import { SuiRating } from "@shineui/angular"; @Component({ standalone: true, imports: [SuiRating], template: `<sui-rating label="How was reconciliation?" name="csat" value="4" show-count help="Feedback goes to the support team." (suiChange)="onChange($event)"></sui-rating>`, }) export class Example { onChange(e: CustomEvent) { console.log(e.detail); } }

Basic

The stars are a role="radiogroup" and only the selected star is tabbable, so Tab lands on the current value. Clicking the selected star clears the rating.

<sui-rating label="How was reconciliation?" name="csat" value="4" show-count help="Feedback goes to the support team."></sui-rating>

Half stars

allow-half picks a half from the leading side of a star, steps by a half on the arrow keys, and posts the decimal. The checked star reads "3.5 of 5" to a screen reader.

<div style="display:flex;flex-direction:column;gap:14px;align-items:flex-start"> <sui-rating id="rt-half" label="Rate this reply" name="reply" allow-half value="3.5" show-count></sui-rating> <sui-rating id="rt-half-avg" label="Average this quarter" allow-half value="4.5" readonly show-count help="Across 128 responses."></sui-rating> </div>

Sizes and counts

Star size is sm 13px, md 16px and lg 20px. count sets how many stars render; the aria-label on each star reads "3 of 5".

<div style="display:flex;flex-direction:column;gap:14px;align-items:flex-start"> <sui-rating id="rt-sm" label="Support reply" value="5" size="sm" show-count></sui-rating> <sui-rating id="rt-md" label="Onboarding call" value="3" show-count></sui-rating> <sui-rating id="rt-lg" label="Overall experience" value="4" size="lg" show-count></sui-rating> <sui-rating id="rt-three" label="Was this article useful?" value="2" count="3" show-count></sui-rating> </div>

States

readonly keeps the rated star in the tab order and announces read-only, as a native read-only input stays focusable, while a click, the arrows and the hover preview change nothing; disabled leaves the tab order. Neither holds the form on valueMissing, because a user cannot clear an error they cannot change.

<div style="display:flex;flex-direction:column;gap:14px;align-items:flex-start"> <sui-rating id="rt-ro" label="Average this quarter" value="4" readonly show-count help="Across 128 responses."></sui-rating> <sui-rating id="rt-off" label="Closed survey" value="3" disabled></sui-rating> <sui-rating id="rt-err" label="How was reconciliation?" required error="Pick a rating before sending."></sui-rating> </div>

In a form

A rated control posts the number and an unrated one posts an empty string. required holds the form until a star is picked.

Submit to see what posts.
<form id="rt-form" style="display:grid;gap:14px;justify-items:start"> <sui-rating label="How was reconciliation?" name="csat" required></sui-rating> <sui-rating label="How was the support reply?" name="support" value="4"></sui-rating> <sui-button type="submit" variant="brand" label="Send feedback"></sui-button> <output id="rt-form-out" style="font:460 13px/1.6 var(--font-sans);color:var(--ink-muted)">Submit to see what posts.</output> </form>
// setup(root): properties and events setup(root) { const form = root.querySelector('#rt-form'); const out = root.querySelector('#rt-form-out'); form.addEventListener('submit', (e) => { e.preventDefault(); out.textContent = [...new FormData(form)].map(([k, v]) => `${k}=${v}`).join(' '); }); }

Events

suiChange carries the new value. Clicking the selected star clears the rating and reports 0.

Idle.
<div style="display:flex;gap:16px;align-items:center;flex-wrap:wrap"> <sui-rating id="rt-events" label="Rate this export" name="export" value="3"></sui-rating> <span id="rt-log" style="font:460 13px/1.6 var(--font-sans);color:var(--ink-muted)">Idle.</span> </div>
// setup(root): properties and events setup(root) { const el = root.querySelector('#rt-events'); const log = root.querySelector('#rt-log'); el.addEventListener('suiChange', (e) => { log.textContent = e.detail === 0 ? 'suiChange 0. Rating cleared.' : `suiChange ${e.detail}.`; }); }

Keyboard

KeyAction
TabMoves to the rated star, or to the first star when nothing is rated. A read-only rating keeps this stop and announces read-only; a disabled one is passed over.
ArrowRight ArrowUpRaises the rating one star, or a half with allow-half, and moves focus with it. Under dir="rtl" the pair swaps, so the arrow that points along the reading direction is always the forward one.
ArrowLeft ArrowDownLowers it by the same step, stopping at the lowest rating, never at none.
Home EndJumps to the lowest rating or to all the stars.
Enter SpacePicks the focused star, or clears the rating when that star is already selected.

API

<sui-rating>

Properties

PropertyAttributeTypeDefaultDescription
allowHalfallow-halfbooleanfalseHalf stars. The leading half of a star (its left, or its right under dir="rtl") picks n.5, the arrow keys step by a half, and the value and the posted form entry carry the decimal (2.5). Without it a decimal value rounds up on screen to the next whole star.
countcountnumber5Number of stars.
disableddisabledbooleanfalseDisables the stars. A disabled rating posts nothing and never holds the form.
errorerrorstringstring | undefinedError message under the stars; also sets aria-invalid.
helphelpstringstring | undefinedHelp text under the stars. Replaced by error when set.
labellabelstringstring | undefinedLabel before the stars; also names the radiogroup.
namenamestringstring | undefinedForm control name. Posts the number, or an empty string while nothing is rated; a disabled rating posts nothing. Reflected: entry construction reads the content attribute, and the three framework bindings set props, so an unreflected name would post nothing.
readOnlyreadonlybooleanfalseDisplay only, as a native read-only input: the rated star keeps its tab stop and the stars announce read-only, but a click, the hover preview and the arrow keys change nothing, and the value still posts. A disabled rating, unlike it, leaves the tab order.
requiredrequiredbooleanfalseA rating must be picked for the surrounding form to be valid. A read-only or disabled rating never holds the form, since the user could not clear the error.
showCountshow-countbooleanfalseShows "4 of 5" after the stars. Its words are translatable (rating.count, {value} of {count}) and its figures follow the page's locale, so a half star reads "2,5" in German.
sizesize"lg" | "md" | "sm"'md'Star size: sm 13px, md 16px, lg 20px.
valuevaluenumber0Current rating, 0 = none. Mutable; updated before suiChange fires.

Events

EventDetailReactVueDescription
suiChangenumberonSuiChange@sui-changeFires when the rating changes; detail is the new value (0 after clearing, n.5 for a half star).

Methods

MethodSignatureDescription
setFocus()setFocus() => Promise<void>Moves keyboard focus to the star that holds the tab stop, as el.focus() does: the rated one, or the first when nothing is rated. sui-form calls this to reach the first invalid control.

Theming

Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.

See also