Skip to content
design
Components

Rating

A rating out of five stars, or of another icon, chosen by pointer, keys or a typed digit.

On this page
Holding

The page receives: 4

An anchorage's holding, rated after a night on the hook: the stars fill to the one the pointer is over.
Code
import { Rating } from "@bosunkit/components/rating";
import { useState, type Dispatch, type ReactElement, type SetStateAction } from "react";

export const description: string =
  "An anchorage's holding, rated by the crew after a night on the hook: the stars fill to the one the pointer is " +
  "over, a press chooses, and a press on the chosen star clears it.";

export default function Showcase(): ReactElement {
  const [holding, setHolding]: [number | null, Dispatch<SetStateAction<number | null>>] = useState<number | null>(4);
  return (
    <div style={{ display: "grid", gap: "var(--space-sm)" }}>
      <Rating label="Holding" value={holding} onValueChange={setHolding} size="lg" />
      <p style={{ margin: 0, color: "var(--text-dim)" }}>
        The page receives: {holding === null ? "no rating" : String(holding)}
      </p>
    </div>
  );
}

A rating is a row of steps, five stars unless max and icon say otherwise, for a place's holding or shelter, a marina or a passage. Each step is a radio named by its value out of the most ("4 of 5"), built on Base UI's radio group: the arrow keys move through the steps and choose as they go, a typed digit chooses its step, and a screen reader says the value. The pointer previews the steps up to the one it is over without choosing; a press chooses. A press on the chosen step clears the rating, as do 0, Backspace and Delete, unless clearable is off. Each step takes the press over a 48 px target whatever size its icon is drawn at; the filled steps take the accent color.

Read-only, the rating is one image named by its value, so an average such as 3.7 reads as "3.7 of 5" and fills that much of the fourth step. name submits the rating with a form, and nothing while there is none.

Examples

An average, read-only

A marina's average from the fleet's ratings, read-only: one image named by its value, 3.7 filling most of the fourth star.
Code
import { Rating } from "@bosunkit/components/rating";
import type { ReactElement } from "react";

export const description: string =
  "A marina's average from the fleet's ratings, read-only: one image named by its value, 3.7 filling most of the " +
  "fourth star.";

export default function Average(): ReactElement {
  return <Rating label="Fleet rating" readOnly value={3.7} />;
}

Another icon and another most

Shelter
Shelter from the swell out of ten, drawn with anchors: any Lucide icon and any number of steps.
Code
import { Rating } from "@bosunkit/components/rating";
import { Anchor } from "lucide-react";
import type { ReactElement } from "react";

export const description: string =
  "Shelter from the swell out of ten, drawn with anchors: any Lucide icon and any number of steps.";

export default function OtherIcon(): ReactElement {
  return <Rating label="Shelter" max={10} icon={Anchor} defaultValue={6} size="sm" />;
}

Sizes

Small
Medium
Large
The three sizes: each step takes the press over a 48 px target whatever size its icon is drawn at.
Code
import { Rating } from "@bosunkit/components/rating";
import type { ReactElement } from "react";

export const description: string =
  "The three sizes: each step takes the press over a 48 px target whatever size its icon is drawn at.";

export default function Sizes(): ReactElement {
  return (
    <div style={{ display: "grid", gap: "var(--space-sm)" }}>
      <Rating label="Small" size="sm" defaultValue={3} />
      <Rating label="Medium" size="md" defaultValue={3} />
      <Rating label="Large" size="lg" defaultValue={3} />
    </div>
  );
}

Disabled

Holding
A rating that cannot be changed until the visit is logged.
Code
import { Rating } from "@bosunkit/components/rating";
import type { ReactElement } from "react";

export const description: string = "A rating that cannot be changed until the visit is logged.";

export default function Disabled(): ReactElement {
  return <Rating label="Holding" disabled defaultValue={2} />;
}

Props

PropTypeDefaultDescription
labelstring | undefined–What is rated, as display text: the group's name ("Holding").
valuenumber | null | undefined–The rating, 1 to max, or null for none, when the caller holds it; read-only, a fraction such as 3.7.
defaultValuenumber | null | undefined–The rating the field starts with when it holds it itself.
onValueChange((value: number | null) => void) | undefined–Called with the rating the crew choose, or null when they clear it.
maxnumber | undefined5The most stars, and the highest rating; 5 when unset.
iconLucideIcon | undefinedStarThe icon each step is drawn with, a Lucide icon; a star when unset.
clearableboolean | undefinedtrueWhether a press on the chosen star, 0, Backspace or Delete clears the rating (the default).
readOnlyboolean | undefined–Shows the rating as an image named by it, a fraction filling part of a step, with nothing to choose.
disabledboolean | undefined–
requiredboolean | undefined–
sizeRatingSize | undefined"md"How large the steps are drawn; md when unset. A step takes the press over a 48 px target whatever its size.
namestring | undefined–Submits the rating with a form under this name; nothing while there is none.
classNamestring | undefined–
testIdstring | undefined–Becomes data-testid on the root.