Prize wheels are popular interactive elements in web applications for gamification, contests, and promotional campaigns. This guide walks through building a customizable, production-ready prize wheel component using React and TypeScript.
Overview
After evaluating existing solutions, most prize wheel libraries lacked flexibility, TypeScript support, or modern React patterns. This implementation addresses these gaps with a fully typed, customizable component built on modern web technologies.
Technical Stack
- React 18 for the component architecture
- TypeScript 5 for type safety
- GSAP for smooth animations
- SVG for scalable rendering
- Vite for build tooling
Core Features
The component provides several essential capabilities:
Probability-Based Selection
Not all prizes should have equal chances. The system uses weighted random selection where each sector has a probability value:
const sectors = [
{ id: 1, label: 'Common', probability: 50 }, // 50% chance
{ id: 2, label: 'Uncommon', probability: 30 }, // 30% chance
{ id: 3, label: 'Rare', probability: 15 }, // 15% chance
{ id: 4, label: 'Legendary', probability: 5 }, // 5% chance
];
Extensive Customization
Every visual aspect is configurable: colors, shadows, borders, text styling, and animation timing.
Programmatic Control
The wheel exposes a ref API for triggering spins and tracking state:
const wheelRef = useRef<PrizeWheelRef>(null);
wheelRef.current?.spin();
const isSpinning = wheelRef.current?.isSpinning;
Implementation
Here's a basic implementation:
import { useRef } from 'react';
import { PrizeWheel } from '@mertercelik/react-prize-wheel';
import type { Sector, PrizeWheelRef } from '@mertercelik/react-prize-wheel';
import '@mertercelik/react-prize-wheel/style.css';
function App() {
const wheelRef = useRef<PrizeWheelRef>(null);
const sectors: Sector[] = [
{ id: 1, label: 'Prize 1', probability: 10 },
{ id: 2, label: 'Prize 2', probability: 20 },
{ id: 3, label: 'Prize 3', probability: 15 },
{ id: 4, label: 'Prize 4', probability: 5 },
];
const handleSpinEnd = (sector: Sector) => {
console.log('Winner:', sector.label);
};
return (
<div>
<PrizeWheel
ref={wheelRef}
sectors={sectors}
onSpinEnd={handleSpinEnd}
/>
<button onClick={() => wheelRef.current?.spin()}>
Spin the Wheel
</button>
</div>
);
}
Customization Options
The component supports extensive styling:
<PrizeWheel
ref={wheelRef}
sectors={sectors}
onSpinStart={handleSpinStart}
onSpinEnd={handleSpinEnd}
duration={6}
minSpins={4}
maxSpins={4}
frameColor="#ffd700"
middleColor="#ffd700"
middleDotColor="#8b7500"
winIndicatorColor="#ffd700"
winIndicatorDotColor="#8b7500"
sticksColor="#ffd700"
wheelColors={['#0a1d3f', '#0a2249']}
borderColor="#ffd700"
borderWidth={3}
textColor="#ffffff"
textFontSize={20}
wheelShadowColor="#000"
wheelShadowOpacity={0.2}
middleShadowColor="#000"
middleShadowOpacity={0.25}
indicatorShadowColor="#000"
indicatorShadowOpacity={0.3}
/>
Animation System
GSAP handles the rotation with easing for natural deceleration. The wheel calculates the final rotation angle based on the selected sector and applies random spins for visual effect.
SVG Rendering
Using SVG ensures the wheel scales perfectly on any screen size. The component generates sector paths dynamically based on the number of sectors and handles text positioning with automatic wrapping for long labels.
Probability Algorithm
The weighted random selection works by calculating total probability weight and using a random value to select a sector:
const totalWeight = sectors.reduce((sum, s) => sum + s.probability, 0);
let random = Math.random() * totalWeight;
for (const sector of sectors) {
random -= sector.probability;
if (random <= 0) return sector;
}
Use Cases
This approach works well for:
- E-commerce promotional campaigns
- Gaming reward systems
- Event raffles
- Interactive landing pages
- Loyalty programs
Installation
npm install @mertercelik/react-prize-wheel
Live Demo
You can try it here: https://mertercelik.github.io/react-prize-wheel/
Resources
- GitHub: https://github.com/mertercelik/react-prize-wheel
- npm: https://www.npmjs.com/package/@mertercelik/react-prize-wheel
Conclusion
Building a reusable wheel component requires careful consideration of customization, animation performance, and probability distribution. This implementation provides a flexible solution that handles various use cases while maintaining type safety and smooth performance.
The project is open source under MIT license. The code and documentation are available on GitHub.
Credit: SVG wheel design inspired by Soma Szoboszlai's work.
Top comments (0)