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 |
| undefined | The tone of the fill; overridden pointwise by the `--gr-rating-color` variable. When not set — from `GrConfigProvider`, otherwise `warning`. |
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;
tone: GrRatingTone;
}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.
In GrFormField the scale is named by the label of the field — through an aria-labelledby
reference: a div with a role is not labelable, and <label for> does not reach it. In the
read-only mode the rating joins the same reference, otherwise the label of the field would replace
it. An ariaLabel of your own is stronger than the label of the field.
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, read from GrConfigProvider, otherwise warning |
--gr-rating-color | the colour of the fill pointwise, stronger than tone |
--gr-rating-void-color | the colour of an unfilled symbol |
--gr-rating-void-fill, --gr-rating-void-stroke, --gr-rating-stroke-width | whether an empty star is filled or outlined — a decision of the theme |
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