react-wagon-wheel-picker
v0.1.7
Published
A playful, interactive radial selection component for React - perfect for kids' apps, games, and fun interfaces
Maintainers
Readme
Wagon Wheel Picker
A playful, interactive radial selection component for React. Perfect for kids' apps, game UIs, and fun, lighthearted interfaces. Display options in a circular wagon wheel layout with bouncy animations and delightful hover effects.

✨ Features
- Playful radial layout - Options arranged in a circular wagon wheel pattern
- Bouncy animations - Springy, playful transitions powered by Framer Motion
- Fully customizable - Themeable colors, sizing, and behavior
- Framework flexible - Works with Next.js Image or standard img tags
- Responsive - Auto-detects mobile or accepts manual size control
- TypeScript support - Full type definitions included
- Lightweight - Minimal dependencies
Perfect For
- Kids' apps and educational games
- Playful e-commerce product pickers
- Character or avatar selectors
- Game lobbies and casual game UIs
- Any interface that benefits from a fun, whimsical touch
📦 Installation
npm install react-wagon-wheel-picker framer-motionNote: Framer Motion is required for the bouncy, playful animations that make this component fun
Bundle Size Optimization: This package uses Framer Motion's lightweight
mcomponent withLazyMotionanddomAnimationfeatures. When you use this package, framer-motion will only add approximately 15KB to your bundle (compared to ~50KB+ if you used the full framer-motion library directly).
🚀 Quick Start
Basic Usage
import { WagonWheelPicker } from 'react-wagon-wheel-picker';
function MyComponent() {
const [selected, setSelected] = useState('option1');
const options = [
{ key: 'option1', label: 'Option 1', image: '/images/option1.png' },
{ key: 'option2', label: 'Option 2', image: '/images/option2.png' },
{ key: 'option3', label: 'Option 3', image: '/images/option3.png' },
];
return (
<WagonWheelPicker
options={options}
value={selected}
onClick={setSelected}
/>
);
}With Next.js Image Component
import Image from 'next/image';
import { WagonWheelPicker } from 'react-wagon-wheel-picker';
function MyComponent() {
return (
<WagonWheelPicker
options={options}
value={selected}
onClick={setSelected}
ImageComponent={Image}
/>
);
}Object Format (Alternative)
const options = {
beef: { label: 'Beef', image: '/beef.png' },
chicken: { label: 'Chicken', image: '/chicken.png' },
pork: { label: 'Pork', image: '/pork.png' },
};
<WagonWheelPicker options={options} value="beef" onClick={handleClick} />Simple String Format
const options = {
option1: '/images/option1.png',
option2: '/images/option2.png',
option3: '/images/option3.png',
};
<WagonWheelPicker options={options} value="option1" onClick={handleClick} />With Different Center Images
const options = [
{
key: 'beef',
label: 'Beef',
image: '/beef-small.png', // Image shown in wedge
centerImage: '/beef-large.png' // Different image shown in center when selected
},
{
key: 'chicken',
label: 'Chicken',
image: '/chicken-small.png',
centerImage: '/chicken-large.png'
},
];
<WagonWheelPicker options={options} value="beef" onClick={handleClick} />Interactive Examples
View Live Storybook Demo - Explore all features interactively!
Or run locally:
npm run storybookThis opens an interactive playground at http://localhost:6006 with:
- 15+ example stories showcasing different use cases
- Live controls to experiment with props and themes
- Multiple themes (dark, colorful, pastel)
- Different sizes and option counts
- Mobile vs Desktop comparison
- Documentation for all props and features
To build a static Storybook:
npm run build-storybook🎨 Customization
Custom Theme
const customTheme = {
tertiaryBackground: '#e3f2fd', // Selected option background
surfaceBackground: '#ffffff', // Unselected option background
tertiary: '#2196f3', // Selected option border
border: '#cccccc', // Unselected option border
background: '#fafafa', // Center circle background
text: '#333333', // Center text color
divider: '#e0e0e0', // Center circle border
};
<WagonWheelPicker
options={options}
theme={customTheme}
/>Custom Sizing
<WagonWheelPicker
options={options}
size={500} // Custom size in pixels
innerPercent={0.35} // Inner radius (35% of total)
outerPercent={0.95} // Outer radius (95% of total)
/>Custom Center Text
<WagonWheelPicker
options={options}
centerText={['PICK', 'YOUR', 'FLAVOR']}
fontFamily="'Arial', sans-serif"
/>📖 API Reference
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| options | Array \| Object | required | Options to display (min 3, max 8 recommended) |
| value | string | undefined | Currently selected option key |
| onClick | function | undefined | Callback when option is clicked: (key: string) => void |
| theme | object | Default theme | Theme object for colors |
| size | number | 420 / 320 | Size in pixels (desktop/mobile) |
| isMobile | boolean | Auto-detected | Force mobile sizing |
| innerPercent | number | 0.4 | Inner radius (0-1) |
| outerPercent | number | 0.9 | Outer radius (0-1) |
| ImageComponent | Component | img | Custom image component |
| centerText | string[] | ['SELECT', 'YOUR', 'OPTION'] | Center text lines |
| fontFamily | string | 'serif' | Font for center text |
| fallbackImage | string | '/fallback.png' | Image when none provided |
Option Format
Array format:
{
key: string; // Required: unique identifier
label?: string; // Optional: display label
image?: string; // Optional: image URL for wedge
centerImage?: string; // Optional: different image for center circle when selected
}Object format:
{
[key: string]: {
label?: string;
image?: string;
centerImage?: string;
} | string // or just image URL
}Theme Format
{
tertiaryBackground?: string; // Selected option fill
surfaceBackground?: string; // Unselected option fill
tertiary?: string; // Selected option border
border?: string; // Unselected option border
background?: string; // Center circle fill
text?: string; // Center text color
divider?: string; // Center circle border
}🎯 Best Practices
- 3-8 options: The component works best with 3-8 options. Fewer than 3 or more than 8 may look cramped or sparse.
- Square images: Use square images for best results in the circular layout.
- Consistent sizing: Keep image dimensions consistent across all options.
- High contrast: Ensure good contrast between theme colors for accessibility.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT © Reed Black
🐛 Issues
Found a bug? Open an issue
💡 Inspiration
Created for Taco Ninja - a playful recipe randomizer app.
