# 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.

Source: https://ngwr.dev/reference/components/rating  
Kind: Signal Forms

## Installation

```angular-ts
import { WrRating } from 'ngwr/rating';

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

## Basic

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

## Half stars

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

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

## Custom count

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

## Read-only

Use to display an existing rating without interaction.

```angular-html
<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](https://ngwr.dev/guides/forms) 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

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `count` | Total number of slots. | `number` | `5` |
| `step` | Step granularity — `1` for whole stars, `0.5` for halves. | `0.5 \| 1` | `1` |
| `readonly` | Read-only — value is displayed but not interactive. | `boolean` | `false` |
| `disabled` | Disable interaction. Bound automatically from the field's disabled state when used with `[formField]`. | `boolean` | `false` |
| `size` | Control size — scales the icons + gaps. | `WrRatingSize` | `'md'` |
| `ariaLabel` | Accessible label. Falls back to `rating.label`, then `'Rating'`. | `string \| null` | `null` |
| `value` | The rating. Bound by `[formField]`, or two-way via `[(value)]`. | `number \| null` | `null` |
| `(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.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-rating-empty` | `var(--wr-color-outline)` | `.wr-rating` |
| `--wr-rating-filled` | `var(--wr-color-warning, #ffba00)` | `.wr-rating` |
| `--wr-rating-gap` | `0.125rem` | `.wr-rating` +2 variant overrides |
| `--wr-rating-size` | `1.25rem` | `.wr-rating` +2 variant overrides |
