Rate

free

Rate captures a star or symbol score for reviews, feedback, and quality ratings.

Preview
Dark
How was your experience?

Your rating helps us improve future orders.

3 out of 5
import { useState } from 'react';
import Rate from '@/components/ui/Rate';

export default function UsageDemo() {
  const [score, setScore] = useState(3);

  return (
    <div className="flex flex-col gap-4">
      <div>
        <div className="text-base font-semibold text-foreground">
          How was your experience?
        </div>
        <p className="text-muted-foreground">
          Your rating helps us improve future orders.
        </p>
      </div>

      <Rate
        value={score}
        onChange={setScore}
        label={score > 0 ? `${score} out of 5` : 'Tap a star to rate'}
      />
    </div>
  );
}

Installation

Add this component with the NateUI CLI.

npx nateui@latest add Rate

Examples

Basic

Preview
Dark
import Rate from '@/components/ui/Rate';

export default function BasicDemo() {
  return <Rate defaultValue={3} />;
}

Half Ratings

Preview
Dark
3.5 stars
import { useState } from 'react';
import Rate from '@/components/ui/Rate';

export default function HalfRatingsDemo() {
  const [value, setValue] = useState(3.5);

  return (
    <Rate
      allowHalf
      value={value}
      onChange={setValue}
      label={`${value.toFixed(1)} stars`}
    />
  );
}

Count

Preview
Dark
import Rate from '@/components/ui/Rate';

export default function CountDemo() {
  return <Rate count={10} defaultValue={7} />;
}

Custom Character

Preview
Dark
import Rate from '@/components/ui/Rate';
import { PiHeart } from 'react-icons/pi'

const sentiments = ['Poor', 'Fair', 'Good', 'Very Good', 'Excellent'];

export default function CustomCharacterDemo() {
  return (
    <Rate
      defaultValue={4}
      tooltips={sentiments}
      character={<PiHeart fill="currentColor" />}
    />
  );
}

States

Preview
Dark
Read only
4.0 average
Disabled
import Rate from '@/components/ui/Rate';

export default function StatesDemo() {
  return (
    <div className="flex flex-col gap-8">
      <div className="flex flex-col gap-2">
        <span className="text-xs uppercase tracking-wide text-muted-foreground">
          Read only
        </span>
        <Rate value={4} readOnly label="4.0 average" />
      </div>
      <div className="flex flex-col gap-2">
        <span className="text-xs uppercase tracking-wide text-muted-foreground">
          Disabled
        </span>
        <Rate value={3} disabled />
      </div>
    </div>
  );
}

Controlled

Preview
Dark
Current rating: 2
import { useState } from 'react';
import Rate from '@/components/ui/Rate';
import Button from '@/components/ui/Button';

export default function ControlledDemo() {
  const [value, setValue] = useState(2);

  return (
    <div className="flex flex-col gap-4">
      <Rate value={value} onChange={setValue} />
      <div className="flex items-center gap-4">
        <span className="text-xs text-muted-foreground">
          Current rating: <span className="font-medium">{value}</span>
        </span>
        <Button size="sm" onClick={() => setValue(0)}>
          Reset
        </Button>
      </div>
    </div>
  );
}

API

Rate renders a single div with role="slider" and full keyboard support: arrow keys adjust the value by one step, and Home / End jump to the minimum and maximum.

PropDescriptionTypeDefault
valueCurrent rating for controlled usage.number-
defaultValueInitial rating for uncontrolled usage.number0
countNumber of rating items rendered.number5
allowHalfEnables half-step precision by splitting each item into two halves.booleanfalse
allowClearClicking the current value again resets the rating to 0.booleantrue
disabledDims the control and blocks all interaction.booleanfalse
readOnlyDisplays the value at full opacity but blocks interaction.booleanfalse
nameRenders a hidden input so the value submits with a native form.string-
characterCustom rating symbol, either a node or a render function per item.RateCharacterStarIcon
tooltipsNative title text per item, indexed from the first item.string[]-
labelTrailing content rendered after the last item, such as a live readout.ReactNode-
classNamesClass name overrides for the item, icon, and label slots.RateClassNames-
onChangeCalled with the next value when the rating is committed.(value: number) => void-
onHoverChangeCalled with the previewed value as the pointer moves across items.(value: number) => void-
classNameClass names applied to the root element.string-
refRef forwarded to the root div.Ref<HTMLDivElement>-
...nativeDivPropsNative props for the root div.NativeRateDivProps-

Types

type RateCharacter =
  | ReactNode
  | ((props: {
      index: number;
      value: number;
      active: boolean;
    }) => ReactNode);
 
type RateClassNames = {
  item?: string;
  icon?: string;
  label?: string;
};
 
type NativeRateDivProps = Omit<
  ComponentPropsWithRef<'div'>,
  'children' | 'onChange'
>;