SvRating

A star rating control built on the WAI-ARIA slider pattern - with hover preview, keyboard support, optional half steps, and a read-only mode.

SvRating collects a score (a product review) or displays an aggregate (a read-only average with half stars). It is controlled: drive value from your state and update it in onChange. It uses the grid's --sg-rating-* tokens so a standalone rating matches the in-grid rating editor, and it carries the shared editor contract (label, hint, validation, dir/RTL) through SvField. Star aria-labels are localizable via messages.

Related: SvSwitchButton · SvRadioGroup · Buttons & toggles overview

Installation

Add it with the CLI - this drops a ready-to-edit SvRating starter into your app:

Prefer to see it first? npx @svgrid/ui try rating opens it in a throwaway sandbox - no project needed.

Or install the package and import it directly. SvRating ships free in @svgrid/grid and is part of the grid's editor kit - the same control SvGrid mounts when you edit a matching cell:

The examples on this page import from @svgrid/grid:

<script lang="ts">
  import { SvRating } from '@svgrid/grid'

  // The bound value behind each example below.
  let score = $state(0)
</script>
import { SvRating } from '@svgrid/grid'

Example

Open the live example: Rating (Buttons & Toggles)

<script lang="ts">
  import { SvRating } from '@svgrid/grid'
  let score = $state(4)
</script>

<SvRating label="Your rating" value={score} onChange={(v) => (score = v)} />

Props

Prop Type Default Description
value number 0 Current rating (controlled).
onChange (value: number) => void - Fires with the new rating on pick.
max number 5 Number of stars.
allowHalf boolean false Allow half-star precision.
readonly boolean false Show the value without allowing edits.
readOnly boolean false Deprecated alias of readonly, kept for back-compat.
disabled boolean false Dims the control and blocks interaction.
size sm | md | lg md Star size.
name string - Emits a hidden input carrying the numeric value.
label string - Visible field label; also names the group for assistive tech.
hint string - Helper text under the stars.
error string - Error message announced via aria-describedby.
required boolean false Adds aria-required.
invalid boolean false Marks the control invalid.
dir ltr | rtl | auto auto Text direction.
ariaLabel string - Accessible name when there is no visible label.
messages Partial<RatingMessages> - Override the built-in strings (group + per-star labels).
id string auto Root id; label/hint/error ids derive from it.

Helper type: RatingMessages = { label: string; star: string; stars: string } (defaults Rating / star / stars).

Examples

Interactive review with a live label

Read value back to show the picked score as the user hovers and clicks:

<script lang="ts">
  let score = $state(0)
</script>

<SvRating value={score} onChange={(v) => (score = v)} />
<span>{score ? `${score} / 5` : 'Not rated'}</span>

Read-only aggregate with half stars

Combine readonly and allowHalf to render an average like 4.5:

<SvRating readonly allowHalf value={4.5} label="Average rating" />

Localized labels

Override messages to translate the group name and per-star announcements:

<SvRating value={score} onChange={(v) => (score = v)}
  messages={{ label: 'Bewertung', star: 'Stern', stars: 'Sterne' }} />

Custom scale submitted with a form

max is not fixed at five - raise it for a 10-point scale, and give it a name so a plain form submit carries the numeric value in a hidden input:

<form>
  <SvRating
    name="nps"
    label="How likely are you to recommend us?"
    max={10}
    value={score}
    onChange={(v) => (score = v)}
  />
</form>

Theming tip: the stars read --sg-rating-on (filled) and --sg-rating-empty (empty), the same tokens as the in-grid rating editor, so a standalone rating stays visually in sync with one shown in a cell.

Accessibility

More examples

Rating - headless

Styled SvRating (half stars) plus a custom segmented meter, one bound numeric value with live preview.

Open the live example: Rating - headless (Headless Editors)

Sizes

Every control takes the same three sizes, so a dense toolbar and a roomy form can share components.

<script lang="ts">
  import { SvRating } from '@svgrid/grid'

  let score = $state(1)
</script>

<SvRating value={score} size="sm" />
<SvRating value={score} size="md" />
<SvRating value={score} size="lg" />

In a form

The shared field props behave the same on every editor: label names it, hint explains it, and error plus invalid mark it - which is why a validated form does not need per-component handling.

<script lang="ts">
  import { SvRating } from '@svgrid/grid'

  let score = $state(1)
</script>

<SvRating
  value={score}
  label="Label"
  hint="A short hint"
  required
/>

<SvRating
  value={score}
  label="Label"
  error="Something is wrong"
  invalid
/>

See also

Live examples

  • Rating - SvRating: an interactive review widget with a live label, plus a read-only half-star aggregate with a distribution breakdown.
  • Rating - headless - Styled SvRating (half stars) plus a custom segmented meter, one bound numeric value with live preview.