Signal Forms

Rating

Star rating input with whole or half-step granularity. Value type is number | null; [0, count] bounds what the control's own edits produce. Keyboard: arrows step by step, Home / End jump to 0 / max, Delete / Backspace clears.

Installation

import { WrRating } from 'ngwr/rating';

@Component({ imports: [WrRating] })
export class MyComponent {
  protected readonly score = signal<number | null>(0);
}

Basic

<wr-rating [(value)]="score" />

Half stars

step="0.5" enables half-star granularity (hover the left half of a star).

<wr-rating [(value)]="score" step="0.5" />

Custom count

<wr-rating [(value)]="score" [count]="10" />

Read-only

Use to display an existing rating without interaction.

<wr-rating [value]="4.5" step="0.5" [readonly]="true" />

Values outside the range

[0, count] bounds what a click or an arrow key can produce. A value written from OUTSIDE — a form loaded from an API, a model seeded by a query string — is drawn and announced clamped, because a role="slider" cannot report a position past its own maximum, and is left in the model exactly as it stands.

The control does not write the clamp back, and that is the same rule wr-slider and wr-input-number follow. Under [formField] a write the component makes to its own value is indistinguishable from the user moving the stars, so writing back would mark a pristine form dirty on first paint — tripping unsaved-changes guards and opening every validator message before anything had been touched — and would delete the out-of-range value that a max() rule exists to report. The first real interaction commits an in-range number, and the two agree from then on.

The reactive-forms guide has the same table for every value control, beside the two bridge behaviours that catch people out more often: updateOn does not apply to an ngwr control, and a { emitEvent: false } write does not repaint one.

API

NameDescriptionTypeDefault
countTotal number of slots.number5
stepStep granularity — 1 for whole stars, 0.5 for halves.0.5 | 11
readonlyRead-only — value is displayed but not interactive.booleanfalse
disabledDisable interaction. Bound automatically from the field's disabled state when used with [formField].booleanfalse
sizeControl size — scales the icons + gaps.WrRatingSize'md'
ariaLabelAccessible label. Falls back to rating.label, then 'Rating'.string | nullnull
valueThe rating. Bound by [formField], or two-way via [(value)].number | nullnull
(touch)Emitted on blur so a bound field can mark itself touched.void

CSS variables

Custom properties ngwr/rating publishes. Each default below is declared on the component's own selector, so a :root override is shadowed by it — set them on that selector, on a wrapper you scope yourself, or inline on the element. Unlike the BEM class names, these are the supported way to restyle the component.

VariableDefaultDeclared on
--wr-rating-emptyvar(--wr-color-outline).wr-rating
--wr-rating-filledvar(--wr-color-warning, #ffba00).wr-rating
--wr-rating-gap0.125rem.wr-rating +2 variant overrides
--wr-rating-size1.25rem.wr-rating +2 variant overrides