Components Rating

Petal Pro is the full SaaS app this is built for

Auth, billing, admin, and Claude Code integration included. One purchase, unlimited projects.

Rating

A real radio group under the stars: it posts in forms, arrow keys work, and the hover preview is pure CSS. Zero JavaScript.
Interactive

interactive renders a fieldset of real radios: the value posts under name like any form field, arrow keys move between options, the hover preview is pure CSS, and focus-visible rings the focused icon. Zero JavaScript. precision="half" doubles the hit areas so 3.5 is clickable.

Rating
3 out of 5
heex
<form>
<.rating interactive name="score" rating={3} precision="half" include_label />
</form>
The sentiment scale

icon="face" swaps stars for five expressions, each its own colour - the CSAT scale. Faces are ordinal, so they always step whole; fractional display values round to the nearest expression with the label carrying the precision.

How was your experience?
heex
<.rating
interactive
name="csat"
rating={0}
icon="face"
size="lg"
label="How was your experience?"
/>
Display only

Without interactive it's a read-only display: fractional values render partial fills, include_label prints the number beside the icons.

3.5 out of 5
3.5 out of 5
Good
heex
<div class="flex flex-col items-center gap-4">
<.rating rating={3.5} include_label />
<.rating rating={3.5} icon="heart" include_label />
<.rating rating={4.2} icon="face" include_label />
</div>
Bring your own glyph

The :glyph slot swaps in any SVG, and --pc-rating-active-color recolours the active state per instance - one slot and one token for a fully custom scale.

Spice level
heex
<.rating
interactive
name="heat"
rating={3}
label="Spice level"
style="--pc-rating-active-color: var(--color-orange-500)"
>
<:glyph>
<svg viewBox="0 0 24 24" fill="currentColor" class="pc-rating__icon">
<path
fill-rule="evenodd"
d="M12.963 2.286a.75.75 0 00-1.071-.136 9.742 9.742 0 00-3.539 6.176 7.547 7.547 0 01-1.705-1.715.75.75 0 00-1.152-.082A9 9 0 1015.68 4.534a7.46 7.46 0 01-2.717-2.248zM15.75 14.25a3.75 3.75 0 11-7.313-1.172c.628.465 1.35.81 2.133 1a5.99 5.99 0 011.925-3.545 3.75 3.75 0 013.255 3.717z"
clip-rule="evenodd"
/>
</svg>
</:glyph>
</.rating>
Properties
Attribute Type Default Description
class any nil Any additional CSS classes for the rating wrapper
disabled boolean false disable the interactive radios
icon string "star" the icon set. Faces are a five-point sentiment scale (total is ignored)
one of: "star", "heart", "face"
include_label boolean false Whether to include an automatically generated rating label
interactive boolean false render as a radio group: clickable, keyboard-accessible, posts in forms. Requires name
label string "Rating" accessible name for the interactive radio group
label_class any nil Any additional CSS classes for the rating label
label_position string "right" where the generated label sits relative to the icons
one of: "right", "bottom"
name string nil the input name (required when interactive)
precision string "whole" interactive step size. half renders two hit areas per icon so 3.5 is clickable and posts as 3.5 - pure CSS. Faces are an ordinal scale and always use whole
one of: "whole", "half"
rating any 0 The rating to display (integer or float)
rest global
round_to_nearest_half boolean true Whether to round the rating to the nearest half star (eg. 3.3 -> 3.5
size string "md" icon size
one of: "sm", "md", "lg"
star_class any nil Any additional CSS classes for the individual icons. Eg. you could change the size of the stars with 'h-10 w-10'
total integer 5 The total number of icons to display
:glyph slot slot a custom glyph (an svg or icon component) used for every position instead of the built-in sets. Design it to inherit currentColor/fill; recolour the active state with the --pc-rating-active-color CSS variable