Skip to content
v1.3.1
Fit

Rating

A row of stars for capturing or displaying a 0–max score. Interactive by default with hover preview and keyboard control; set readOnly to show a fixed score (optionally with a value/count label), or allowHalf for half-star precision.

bash
jlds add rating

Interactive

Hover to preview, click to set, arrow keys to nudge. The HTML version is driven by rating.js; React/Vue carry their own behavior.

html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/rating.css">
<!-- behavior layer: hover/click/keyboard -->
<script src="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/js/core.js" defer></script>
<script src="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/js/rating.js" defer></script>

<span class="jl-rating" data-value="3" role="slider" aria-label="Rating">
  <span class="jl-rating__stars">
    <button type="button" class="jl-rating__btn" data-fill="full" aria-label="1 star">
      <span class="jl-rating__star" style="position:relative;width:20px;height:20px">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" style="position:absolute;inset:0"><path d="m12 3.2 2.7 5.5 6 .9-4.35 4.24 1.03 6L12 17.1 6.62 19.84l1.03-6L3.3 9.6l6-.9Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></svg>
        <svg class="jl-rating__fg jl-rating__fill" width="20" height="20" viewBox="0 0 24 24" style="position:absolute;inset:0"><path d="m12 3.2 2.7 5.5 6 .9-4.35 4.24 1.03 6L12 17.1 6.62 19.84l1.03-6L3.3 9.6l6-.9Z" fill="currentColor"/></svg>
      </span>
    </button>
    <!-- one .jl-rating__btn per star; data-fill is full | half | empty -->
  </span>
</span>
vue
<script setup lang="ts">
import { ref } from "vue"
import { Rating } from "@/components/ui/rating"
const score = ref(3)
</script>

<template>
  <Rating v-model="score" />
</template>
tsx
import { useState } from "react"
import { Rating } from "@/components/ui/rating"

const [score, setScore] = useState(3)
<Rating value={score} onChange={setScore} />

Add data-allow-half="true" (HTML) / allowHalf (React/Vue) for half-star clicks.

Read-only with value

readOnly locks the score; showValue appends the number and an optional count of ratings. Set tone to recolour the stars.

html
<span class="jl-rating" data-tone="warning" data-readonly="true" role="img" aria-label="Rating: 4.5 of 5">
  <span class="jl-rating__stars">
    <!-- four data-fill="full" stars + one data-fill="half" -->
  </span>
  <span class="jl-rating__value">4.5<span class="jl-rating__count"> (1,284)</span></span>
</span>
vue
<template>
  <Rating :model-value="4.5" read-only allow-half show-value tone="warning" :count="1284" />
</template>
tsx
<Rating value={4.5} readOnly allowHalf showValue tone="warning" count={1284} />

Props

React

Rating extends React.HTMLAttributes<HTMLSpanElement> (minus onChange / defaultValue).

PropTypeDefaultDescription
valuenumberControlled score
defaultValuenumber0Uncontrolled initial score
onChange(value: number) => voidFires on select
maxnumber5Number of stars
allowHalfbooleanfalseAllow half-star values
readOnlybooleanfalseDisplay-only (no interaction)
disabledbooleanfalseDim and disable
size"sm" | "md" | "lg""md"Star size
tone"accent" | "warning" | "danger" | "neutral""accent"Fill colour
showValuebooleanfalseAppend the numeric value
countnumberRating count shown after the value

Vue

Same options. value/onChange become v-model (plus a @change emit); pass aria-label via the ariaLabel prop.

CSS classes (HTML)

ClassPurpose
.jl-rating + [data-value]Host and current score
[data-tone] / [data-readonly] / [data-disabled] / [data-allow-half]Tone and mode flags
.jl-rating__starsStar row
.jl-rating__btn[data-fill]One star; data-fill is full / half / empty
.jl-rating__star / __fg / __fillThe stacked outline + clipped fill glyphs
.jl-rating__value / __countOptional numeric label and count