Spin to Win Wheel React component
A gamified discount-capture widget where visitors spin a weighted SVG prize wheel for a reward, with five glass themes, a themed reveal modal and code copy, rendered inline or as a corner-launched popup with manual/delay/scroll triggers.
About the Spin to Win Wheel component
Spin to Win Wheel is a prize wheel for discounts and promotions. Visitors press the button, the wheel spins for about four seconds and stops on a prize, and a modal shows the prize with its code and a copy button. Each visitor gets a set number of spins (3 by default), and every prize won is listed so they can copy the codes later.
theme loads one of five ready prize sets (ecommerce, campaign, restaurant, saas, event), each with its own title, eight prizes and codes. Prizes are picked with weights, so a 30% discount can be rarer than 5%, and a Try Again slice uses up a spin without giving a prize. The spins left and the prizes won are saved in localStorage, so a reload does not reset them. It can show inline or as a popup that opens from a button, on click, after a delay or on scroll.
When to use it
Use it for newsletter sign-up rewards, first-order discounts, sale campaigns, restaurant promotions and event ticket upsells, where a playful moment makes a discount more memorable.
For a prize revealed with a single roll, use Dice Roll Discount Popup. For a scratch-off reveal, use Scratch Card Popup.
Installation
Add the Spin to Win Wheel component to your project with the shadcn CLI. It lands in components/spin-to-win-wheel.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add @reactframe/spin-to-win-wheelOr copy the source by hand and install its dependencies:
npm install clsx tailwind-mergeProps
<SpinToWinWheel /> accepts 11 props, all optional. It also accepts the usual <div> attributes, like className, style, id and aria-*, and passes them to its root element.
| Prop | Type | Default |
|---|---|---|
| accentColor | string | "#ffffff" |
| theme | "ecommerce" | "campaign" | "restaurant" | "saas" | "event" | "ecommerce" |
| asPopup | boolean | false |
| defaultOpen Only used when asPopup is true — starts the popup open instead of showing the launcher widget. | boolean | false |
| trigger | "manual" | "delay" | "scroll" | "manual" |
| delaySeconds | number | 4 |
| widgetPosition | "bottom-right" | "bottom-left" | "bottom-right" |
| widgetIcon | string | — |
| storageKey | string | "" |
| freeSpins | number | 3 |
| spinDuration | number | 4.2 |
- accentColorstringDefault: "#ffffff"
- theme"ecommerce" | "campaign" | "restaurant" | "saas" | "event"Default: "ecommerce"
- asPopupbooleanDefault: false
- defaultOpen
Only used when asPopup is true — starts the popup open instead of showing the launcher widget.
booleanDefault: false - trigger"manual" | "delay" | "scroll"Default: "manual"
- delaySecondsnumberDefault: 4
- widgetPosition"bottom-right" | "bottom-left"Default: "bottom-right"
- widgetIconstring
- storageKeystringDefault: ""
- freeSpinsnumberDefault: 3
- spinDurationnumberDefault: 4.2
Kits
Sets of components designed to be used together on one site, Spin to Win Wheel included.
Collections
Use-case pages that compare Spin to Win Wheel with the other components that do a similar job.
npm dependencies
Installed for you by the shadcn CLI.
Spin to Win Wheel FAQ
- How do I set my own prizes and codes?
- Prizes come from the theme, not a prop. Edit the segments of a theme in the THEMES object at the top of the file: each one has a label, a code, an optional weight (higher is more likely) and an optional color.
- Are the codes safe from people who read the page source?
- No. The prizes, codes and the spin limit all live in the browser, so anyone can read the codes in the JavaScript or reset their spins by clearing site data. Use codes that are fine to leak, or check them on your server, for example one use per customer.
- How do I give more or fewer spins?
- Set freeSpins. Once a visitor has used their spins, the count is kept in localStorage, so a returning visitor still has none left. Give each campaign its own storageKey to start counts fresh.
- Which slices count as no prize?
- Any slice whose label contains "Try Again" or "retry". It still uses a spin, but nothing is added to the list of prizes won.
- Can I change the spin length?
- Yes. spinDuration is in seconds (4.2 by default). The prize is picked before the wheel starts turning, so the length has no effect on the odds.