Skip to main content

Star Rating

Difficulty: Core

Problem Statement​

Build 5-star rating with hover preview and click to set rating.

Live Demo​

Try the running app below β€” this is the target behavior for the challenge.

Star Rating β€” Live Demo
β˜†β˜†β˜†β˜†β˜†

Current rating: none

What Interviewers Expect​

  • Separate hover index and selected rating.
  • Restore selected rating on mouse leave.
  • Accessible labels/controls.

Step-by-Step Implementation​

Step 1 β€” rating + hover state​

Track both selected rating and temporary hover.

const [rating, setRating] = useState(0);
const [hover, setHover] = useState(0);

Step 2 β€” Active star calculation​

Use hover when present, else rating.

const active = hover || rating;

Step 3 β€” Star interactions​

Mouse enter/leave + click handlers per star.

onMouseEnter={() => setHover(n)}
onClick={() => setRating(n)}

Complete Implementation​

Copy-paste ready single-file solution. Use this as your reference after attempting the challenge yourself, or paste it into CodeSandbox / StackBlitz to run locally.

App.jsx
import React, {useState} from 'react';

export default function App() {
const [rating, setRating] = useState(0);
const [hover, setHover] = useState(0);
const active = hover || rating;

return (
<div>
<div style={{display: 'flex', gap: '0.25rem', fontSize: '1.6rem'}}>
{[1, 2, 3, 4, 5].map((value) => (
<span
key={value}
role="button"
tabIndex={0}
onMouseEnter={() => setHover(value)}
onMouseLeave={() => setHover(0)}
onClick={() => setRating(value)}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') setRating(value);
}}
style={{cursor: 'pointer'}}
>
{value <= active ? 'β˜…' : 'β˜†'}
</span>
))}
</div>
<p style={{color: '#666', fontSize: '0.9rem'}}>
Current rating: {rating || 'none'}
</p>
</div>
);
}

Final Checklist​

  • UI works for primary flow
  • Edge cases handled (empty/disabled/loading where relevant)
  • State updates are immutable
  • Components are readable and reasonably split
  • You can explain trade-offs out loud in an interview

Next Challenge​

Continue to the next item in the sidebar when you're comfortable implementing this from scratch in 30–45 minutes.