GrRating
Collect and display a star rating, with half steps and a read-only mode.
Overview
When to take it
- the rating is given in one click — a review, the quality of support, the difficulty of a task;
- the rating is fractional —
allowHalffor halves; - an explanation is needed beside it —
textslabels the steps with words: “Poor”, “Excellent”; - the rating is shown rather than given —
readonlyfor the average rating in a product card.
When to take something else
| Need | Take |
|---|---|
| The scale is numeric and wide | GrSlider |
| An exact number is needed | GrNumberInput |
| There are few options and they are named | GrRadioGroup |
| Show a share rather than a rating | GrProgressBar |
Variants every tone and view, rendered by the real component
tone
primaryneutralsuccesswarningdangerinfoslateazure
Sizes
xssmmdlg
States
normaldisabledreadonlyinvalid
The grid is live: hover and press it. Hover, focus and active states are not drawn here — they belong to the browser, not to a prop.
Playground controls come from the API, not from hand
Loading…
0 changed· state is in the URL
<GrRating v-model="value" />Examples 3 each with a live demo and its code
A review after delivery
The rating is a radio group in disguise: arrows walk it, and
clearablelets a second click on the same star take the answer back.textsnames each step — «Good», not just «4» — and the word also goes intoaria-valuetext.How was your order?Linen shirt, sand, M · delivered yesterday Fit, fabric, colour — it helps the next buyer
0 / 500Rating a support conversation
The
symbolslot draws faces instead of stars, andfilledlights up every face up to the answer while the rest stay grey. The scale stays a radio group for the keyboard, andtextsstill names the steps for the screen reader.DKChat with Daniel · closedAbout: export to CSV cuts long notesHow did we do?Average ratings in a catalogue
Someone else’s average is not a control:
readonlytakes the scale out of the tab order and draws it as a picture.allow-halfshows 4.5 as four and a half stars,compactdrops the empty ones — in a list grey stars are noise — andshow-textadds the number.Linen shirt, sand€64.0042 reviews4.5Wool cardigan, navy€129.0018 reviews4Canvas tote€18.007 reviews3.5Silk scarf, rust€45.003 reviews5
API generated from the package · cannot drift
Props
| Prop | Type | default | Description |
|---|---|---|---|
disabled | boolean | undefined | false | The scale is unavailable: it stays a slider with `aria-disabled`, but leaves the tab order and does not change. |
tone |
| "warning" | The tone of the fill; overridden pointwise by the `--gr-rating-color` variable. |
icon | string | Component | undefined | undefined | A symbol instead of the built-in star: a Vue component or an icon class (`'i-lucide-heart'` — the application sets up the rule for the class: in the engine factory or through a provider, see the “Icons” section of `docs/installation.md`). |
readonly | boolean | undefined | false | Display only: without input and without focus. |
invalid | boolean | undefined | false | The visual and ARIA state of an error. |
required | boolean | undefined | false | A mandatory field (`aria-required`). |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | The size of the symbols and the label. Unset — from `GrConfigProvider`, otherwise `md`. |
ariaLabel | string | undefined | undefined | The accessible name of the scale: what is being rated — "Delivery quality". By default — from the locale (`Rating`). |
clearable | boolean | undefined | false | A repeated click on the current score resets it to `0`. |
name | string | undefined | undefined | The name for a native form: a hidden input with the value; `0` means "not chosen", and the input is not rendered. |
max | number | undefined | 5 | The number of symbols on the scale. |
compact | boolean | undefined | false | A compact look: only the filled symbols are drawn. It makes sense together with `readonly` — in lists and tables five stars in every row eat the width. |
allowHalf | boolean | undefined | false | Half scores: a click on the left half of a symbol gives `.5`. |
showText | boolean | undefined | false | Show a numeric label to the right of the scale. |
formatText | ((value: number) => string) | undefined | undefined | The format of the label. By default — the value itself. Stronger than `texts`. |
texts | string[] | undefined | undefined | Labels by step: "3 out of 5, fine" instead of "3 out of 5". They go both into the visible text and into `aria-valuetext` — that is what the rating exists for. An array shorter than `max` leaves the upper steps without a label. |
modelValuerequiredv-model | number | — | The current score. A fractional one (`3.5`) is supported with `allowHalf`. |
Slots
| Slot | Type | Description |
|---|---|---|
symbol | { index: number; filled: boolean; } | A symbol of your own instead of the star. `filled` is the filled half of the symbol. |
text | { value: number; } | A label beside the score. |
Events
| Event | Signature | Description |
|---|---|---|
update:modelValue | (event: "update:modelValue", value: number): void | — |
change | (event: "change", value: number): void | — |
clear | (event: "clear"): void | — |
focus | (event: "focus", event: FocusEvent): void | — |
blur | (event: "blur", event: FocusEvent): void | — |
hoverChange | (event: "hoverChange", value: number | null): void | — |
Methods
| Methods | Signature | Description |
|---|---|---|
focus | () => void | Focus the scale from code. In `readonly` the scale is a picture and does not take focus. |
blur | () => void | Remove the focus from the scale. |
Types
Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.
import type { GrRatingConfigurableProps, GrRatingProps, GrRatingEmits } from '@feugene/granularity/components/GrRating'Filedist/types/components/GrRating/config.d.ts
const grRatingConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrRating">;Filedist/types/components/GrRating/defaults.d.ts
interface GrRatingConfigurableProps {
size: GrRatingSize;
}Filedist/types/components/GrRating/GrRating.vue.d.ts
interface GrRatingProps {
modelValue: number;
max?: number;
size?: GrRatingSize;
tone?: GrRatingTone;
allowHalf?: boolean;
readonly?: boolean;
disabled?: boolean;
invalid?: boolean;
required?: boolean;
clearable?: boolean;
icon?: string | Component;
showText?: boolean;
formatText?: (value: number) => string;interface GrRatingEmits {
(e: 'update:modelValue', value: number): void;
(e: 'change', value: number): void;
(e: 'hoverChange', value: number | null): void;
(e: 'clear'): void;
(e: 'focus', event: FocusEvent): void;
(e: 'blur', event: FocusEvent): void;
}Filedist/types/components/GrRating/grRatingStyles.d.ts
type GrRatingSize = GrComponentSize;type GrRatingTone = GrTone;Filedist/types/components/GrRating/safelist.d.ts
const grRatingSafelist: string[];Filedist/types/components/GrRating/index.d.ts
type GrRatingInstance = ComponentExposed<typeof GrRatingComponent>;Accessibility
APG pattern
slider (интерактивный) / img (readonly)
Keys
→ / ↑← / ↓Home / End
Full contract of the package: docs/keyboard.md ↗
Usage from the library prose
The rating in words
<GrRating v-model="score" :texts="['Awful', 'Poor', 'Fair', 'Good', 'Excellent']" show-text />texts holds one label per division. The label goes both into the visible text and into
aria-valuetext (“4 of 5, good”): that is the whole point of a rating — a screen reader reads the
score in words rather than as a bare number. A fractional value is rounded up to its division, and
an array shorter than max leaves the upper divisions without a label.
formatText is stronger than texts for the visible text — the consumer may have a wording of
their own.
The preview
Hovering shows the rating under the cursor and emits hoverChange; leaving the scale and losing
the focus return the model and send hoverChange(null).
The handler hangs on the scale itself rather than on the whole component: the caption lies beside
the scale, and a cursor moved onto it has to put the preview out — otherwise it sticks. In
readonly and disabled there is no preview at all.
There is no preview from the keyboard: the arrows commit the rating at once, and hoverChange is
not emitted there.
The compact look
<GrRating :model-value="3" readonly compact show-text />compact draws only the filled symbols — for tables and lists, where five stars in every row eat
up the width. A half counts as a symbol: “2.5” is drawn with three. For a screen reader the compact
mode is no different — the role and the text label are the same.
The modes and accessibility
An interactive scale implements the slider pattern: role="slider",
aria-valuemin/max/now/valuetext, the arrows, Home/End. The read-only mode is a
role="img" with a text label, so that the rating is read as a single phrase rather than as a set
of elements.
disabled dims the scale with the --gr-disabled-fg token rather than with transparency:
opacity dilutes colours tuned to AA.
Styling
| Point | What it sets |
|---|---|
size | xs…lg, read from GrConfigProvider |
tone | the colour of the fill from the tone scale |
--gr-rating-color | the colour of the fill pointwise, stronger than tone |
--gr-rating-void-color | the colour of an unfilled symbol |
icon / the #symbol slot | a symbol of your own instead of the built-in star |
The default symbol is an inline SVG: the icon masks of i-lucide-star give an outline only. A
symbol of your own is a Vue component or an icon class (i-lucide-* — the application sets up the rule for it: in the engine
factory or through a provider, otherwise a Vue component; see “Icons”).
The native form
The name prop renders an input[type="hidden"] with the value of the rating. 0 means “not
selected”: the input is not rendered, as with an unchecked radio button.
Props in this example