Rating# Component <neo-rating> is a symbol-based rating control (stars by default) following the WAI-ARIA slider pattern: the host is the single focusable slider and the symbols are decorative, so screen readers announce one value instead of max separate widgets. Hover or drag previews; click commits. Keyboard arrows, Home / End, and digit keys preview; Enter commits. Set precision="0.5" to allow half symbols.
The preview routes through the in-browser server simulator. Its current Settings (network latency, a non-200 response, or an unreachable server) are in effect, so the live preview can look like it is misbehaving. Adjust them in the Settings panel.
HTML CSS
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
<neo-rating
data-signals="{rating_value: '3'}"
label="Overall rating"
data-attr:value="$rating_value"
></neo-rating> <neo-rating
role="slider"
value="3"
label="Overall rating"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="5"
aria-valuenow="3"
aria-valuetext="3 / 5"
aria-label="Overall rating"
tabindex="0"
>
<div data-neo-rating-symbols aria-hidden="true">
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
</div>
</neo-rating> <neo-rating
role="slider"
value="2.5"
precision="0.5"
label="Difficulty"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="5"
aria-valuenow="2.5"
aria-valuetext="2.5 / 5"
aria-label="Difficulty"
tabindex="0"
>
<div data-neo-rating-symbols aria-hidden="true">
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 50%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
</div>
</neo-rating> <neo-rating
role="slider"
value="4"
precision="0.5"
label="Average score"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="5"
aria-valuenow="4"
aria-valuetext="4 / 5"
aria-label="Average score"
readonly
aria-readonly="true"
tabindex="-1"
>
<div data-neo-rating-symbols aria-hidden="true">
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
</div>
</neo-rating> <neo-rating
role="slider"
value="2"
label="Locked rating"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="5"
aria-valuenow="2"
aria-valuetext="2 / 5"
aria-label="Locked rating"
disabled
aria-disabled="true"
tabindex="-1"
>
<div data-neo-rating-symbols aria-hidden="true">
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
</div>
</neo-rating> <neo-rating
role="slider"
value="7"
max="10"
label="Score out of 10"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="10"
aria-valuenow="7"
aria-valuetext="7 / 10"
aria-label="Score out of 10"
tabindex="0"
>
<div data-neo-rating-symbols aria-hidden="true">
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
</div>
</neo-rating> <neo-rating
role="slider"
value="4"
icon="heart"
label="Favourite"
size="lg"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="5"
aria-valuenow="4"
aria-valuetext="4 / 5"
aria-label="Favourite"
tabindex="0"
>
<div data-neo-rating-symbols aria-hidden="true">
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="heart"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="heart"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="heart"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="heart"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="heart"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="heart"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="heart"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="heart"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="heart"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="heart"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="heart"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="heart"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="heart"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="heart"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="heart"></neo-icon>
</span>
</span>
</div>
</neo-rating> <neo-rating
role="slider"
value="3"
precision="0.5"
label="Spice level"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="5"
aria-valuenow="3"
aria-valuetext="3 / 5"
aria-label="Spice level"
tabindex="0"
class="rating-fire"
>
<div data-neo-rating-symbols aria-hidden="true">
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 100%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
<span data-neo-rating-symbol>
<span data-neo-rating-empty><neo-icon name="star"></neo-icon></span>
<span data-neo-rating-preview style="width: 0%">
<neo-icon name="star"></neo-icon>
</span>
<span data-neo-rating-full style="width: 0%;">
<neo-icon name="star"></neo-icon>
</span>
</span>
</div>
</neo-rating> .rating-fire {
--neo-rating-color: #f97316;
--neo-rating-empty-color: color-mix(
in srgb, #f97316 22%, transparent);
--neo-rating-symbol-gap: 0.5rem;
}
Reference# Attributes # Name Type Default Description valuenumber reflected observed0Current rating, clamped to [0, max] and snapped to precision. maxnumber observed5Number of symbols. precisionnumber observed1Smallest selectable step in (0, 1]. 0.5 gives half symbols, 0.25 quarters. iconstring observed"star"neo-icon name drawn for each symbol (e.g. heart).labelstring observednone Accessible name; mirrored to aria-label unless an aria-labelledby is already set. size"" | "sm" | "lg"""Symbol size shorthand for --neo-rating-symbol-size. readonlyboolean observedfalseDisplay-only: announced to AT but not interactive and out of the tab order. disabledboolean observedfalseRead-only plus a dimmed, non-interactive appearance.
Events # Name Detail Bubbles Description neo-rating-input{ value: number }yes Fires continuously while previewing (hover, drag, or keyboard candidate) with the value not yet committed. neo-rating-change{ value: number }yes Fires on commit (click, drag end, keyboard Enter) and only when the value actually changed.
Parts # Name Description ::part(svg)The symbol's <svg>, forwarded from the nested <neo-icon> so its fill and stroke can be styled.
CSS variables # Name Default Description --neo-rating-symbol-size1.5remSymbol size. --neo-rating-symbol-gap0.15remGap between symbols. --neo-rating-color#f59e0bColor of filled symbols. --neo-rating-preview-colorvar(--neo-rating-color)Color of the preview shown while hovering or dragging. --neo-rating-empty-colorvar(--btn-border)Color of empty symbols. --neo-rating-transition-durationcalc(120ms * var(--neo-duration-scale, 1))Fill transition duration.
Examples# Basic# Five stars, whole-symbol steps. Click a star or focus the control, preview with a digit / arrow key, and press Enter to commit.
Half-symbol precision# With precision="0.5" the left half of a symbol selects the half value and the right half the whole one; pointer and arrow keys both step by 0.5.
Read-only# readonly shows an aggregate score: it is still announced to assistive tech but takes no pointer or keyboard input and stays out of the tab order.
Disabled# disabled is read-only plus a dimmed, non-interactive look; use it when the rating is temporarily unavailable.
Custom range# max sets the symbol count; here a score out of ten.
Customization# The symbol is any neo-icon via the icon attribute, and three CSS custom properties drive the look: --neo-rating-color (filled), --neo-rating-empty-color (track), and --neo-rating-symbol-size / --neo-rating-symbol-gap. The size attribute is a shorthand for the common small / large symbol sizes.
Hearts, large# icon="heart" swaps the symbol; size="lg" scales it up.
Themed via custom properties# A scoped class redefines the --neo-rating-* variables (a warm ember palette with wider spacing) without touching the component itself.