v1.0.0

<bmx-rating>

A row of stars that submits a number. Click one, drag across them, or arrow between them; halves if you want them, and a caption that says what the icons cannot.

23 properties · 3 events · 5 methods · 6 parts

Example

Show markup
<div class="row">
  <bmx-rating label="How was your stay?" description="Click a star, drag across them, or tab to the row and use the arrow keys."></bmx-rating>
</div>
<div class="row">
  <bmx-rating label="Food" allow-half="true" clearable="true" show-value="true" description="Halves, and clicking the current star again takes the rating back off."></bmx-rating>
</div>
<div class="row">
  <bmx-rating label="Average score" value="4.5" allow-half="true" readonly="true" show-value="true" description="Read-only: an image with a name, not a control in the tab order."></bmx-rating>
</div>
<div class="row">
  <bmx-rating id="ex-rating-worded" label="Recommend us" icon="heart" tone="danger" max="5" description="Another glyph, and wording of its own."></bmx-rating>
</div>
<script type="module">
  await customElements.whenDefined('bmx-rating');

  // `format` is a function, so it is a property. One function supplies both the
  // caption and `aria-valuetext`, which is what stops a rating showing "Loved
  // it" while announcing "5".
  const words = ['No answer yet', 'Never', 'Unlikely', 'Perhaps', 'Probably', 'Certainly'];

  document.getElementById('ex-rating-worded').format = value => words[Math.round(value)];
</script>

WHY IT IS A SLIDER AND NOT A RADIO GROUP

A rating reads like a small set of answers, which is a radio group, and it behaves like one - arrow keys move between the answers and change the value as they go - so it takes its keyboard from src/core/choice.ts unchanged, including the rule that Up and Down never flip in a right-to-left layout while Left and Right always do.

The ARIA role is slider even so, and the reason is halves. A five-star rating with halves has ten answers drawn as five glyphs, and a radio group would have to publish ten radios to match - so a screen reader user hears "two and a half stars, radio button, six of ten" while a sighted user sees five stars. A slider carries the same value as one number, with the maximum beside it, and aria-valuetext says it in words. One control, one value, one announcement.

A read-only rating is neither. Showing an average alongside a review is not a control at all - it is a picture of a number, and the great majority of ratings on any site are this - so it renders as role="img" with the value as its accessible name, and takes no place in the tab order. A widget nobody can operate is worse than a label.

WHY THE ICON IS A PATH AND NOT A SLOT

A slot puts its assigned node in exactly one place. Five icons need five copies, and there is no markup that says "put this element here five times" - so icon names one of the shapes below and iconPath takes a path of your own, in a 24x24 box. It is the same trade bmx-button makes for its spiral.

HALVES ARE DRAWN, NOT CHOSEN FROM A SECOND GLYPH

Each icon is the empty shape with a filled copy laid over it, clipped to a width. That is one shape rather than two, so a half cannot shimmer along the seam; it is expressed as inline-size, so a right-to-left layout fills from the correct edge without a second rule; and the fill is a percentage, so a consumer showing 4.3 as 30% of the fifth star needs nothing added here.

ACCESSIBILITY

  • One tab stop, on the row, not five.
  • aria-valuetext says "3 of 5 stars", because aria-valuenow="3" on its own is a number with no unit and no scale.
  • The hover preview never survives the pointer leaving, and never reaches assistive technology: it is a sighted affordance, and announcing every star the mouse crosses would be unusable.
  • Read-only ratings are images with names; disabled ones are not focusable.

Properties

PropertyAttributeTypeDefaultDescription
allowHalf allow-half boolean false Let the user pick halves. Doubles the answers, not the icons.
autoFocus auto-focus boolean false Focus the field once it has rendered.
clearable clearable boolean false Let the user take the rating back off. Off by default: a rating is usually being asked for rather than offered. With it on, clicking the current value again clears it, and so does arrowing back off the lowest star - which is the only way to undo a rating from the keyboard, since there is no "none of these" to arrow onto.
description description string Help text below the field.
disabled disabled boolean false Disable the field.
emptyText empty-text string 'No rating' What an unrated field is announced as.
errorText error-text string An error supplied by the consumer - a server response, typically.
format property only BmxRatingFormatter Your own wording for the announcement and the caption. One function for both, so a rating cannot end up showing "Good" and announcing "4".
hideLabel hide-label boolean false Hide the label visually while keeping it for assistive technology.
icon icon BmxRatingIcon 'star' Which glyph.
iconPath icon-path string Your own glyph, as a path in a 24x24 box. Overrides icon.
label label string The field's label. Required unless the label slot is used.
max max number 5 How many icons.
messages property only BmxFieldMessages Replacements for the default wording, by reason. Accepts the JSON spelling of the object as well, for templates that can only write attributes. See src/core/markup.ts.
name name string The field's name in the form it belongs to.
readonly readonly boolean false Show the rating without letting it be changed. Renders as an image.
required required boolean false Require a rating.
showValue show-value boolean false Show the value beside the icons.
size size BmxSize 'md' Size step.
tone tone BmxTone 'warning' Semantic colour role. warning by default, alone in this library, because that is the amber a five-star rating is drawn in everywhere. A rating in the primary blue is not a rating anybody recognises, and defaulting to consistency here would cost more than it bought.
unit unit string 'star' The noun in the announcement. Pluralised by adding an s.
validateOn validate-on BmxValidateOn 'blur' When the field is willing to reveal a problem.
value value number 0 The rating. Zero means no rating, which is not the same as one star.

Events

EventDetailDescription
bmxChange BmxRatingChangeDetail Fired when the value is committed.
bmxInput BmxRatingChangeDetail Fired as the value changes during a drag.
bmxValidityChange BmxRatingValidityDetail Fired whenever the resolved validity changes.

Methods

MethodSignatureDescription
checkValidity checkValidity() => Promise<boolean> Validate now and return whether the field passed, without revealing it.
clear clear() => Promise<void> Take the rating off, whatever clearable says.
removeFocus removeFocus() => Promise<void> Remove focus from the field.
reportValidity reportValidity() => Promise<boolean> Validate, reveal any problem, and focus the field if it has one.
setFocus setFocus(options?: FocusOptions) => Promise<void> Focus the field.

Slots

SlotDescription
description Rich help text, in place of the description property.
label Rich label content, in place of the label property.

CSS shadow parts

PartDescription
description The help text.
error The error message.
field The row of icons.
icon One icon.
label The label element.
value The value caption, when showValue is on.

CSS custom properties

PropertyDescription
--bmx-rating-color The filled colour. Follows tone unless overridden.
--bmx-rating-empty-color The unfilled colour.
--bmx-rating-gap Space between icons.
--bmx-rating-hover-color The filled colour while the pointer is over the row.
--bmx-rating-label-font-size The label's font size.
--bmx-rating-size The height and width of one icon.
--bmx-rating-stack-gap Space between the label, the row and the supporting text.
--bmx-rating-support-font-size Font size of the description, error and value caption.