Package Exports
- @marcosfreitas/pastel-color-picker
- @marcosfreitas/pastel-color-picker/css
- @marcosfreitas/pastel-color-picker/headless
- @marcosfreitas/pastel-color-picker/style.css
Readme
🎨 Pastel Color Picker
A comprehensive React color picker component with multiple variants, pastel color support, and alpha channel control. Built with Radix UI primitives and styled with Tailwind CSS.
✨ Features
- 🎯 Multiple Variants: Button, Circles, Simple, and Random color selection modes
- 🌈 Pastel & Vibrant Colors: Toggle between soft pastel and vibrant color palettes
- 💧 Alpha Channel Support: Control transparency with optional alpha slider
- 📱 Responsive Design: Works perfectly on both small and large screens
- 🎨 Custom Presets: Define your own color palettes
- ♿ Accessibility: Full keyboard navigation and screen reader support
- 🔧 TypeScript: Complete type safety with detailed interfaces
- ⚡ Modern Stack: Built with Radix UI primitives and Tailwind CSS
🎯 How It Works
The color picker uses the HSL (Hue, Saturation, Lightness) color model, which provides an intuitive way to select colors by separating color properties:
🌈 Color Theory
HSL Color Model Components:
- Hue (H): The color type (0-360°) - Red, Orange, Yellow, Green, Blue, Purple, etc.
- Saturation (S): Color intensity (0-100%) - Gray to Vivid
- Lightness (L): Brightness (0-100%) - Black to White
🔄 User Selection Process
🎨 Choose Base Color (Hue)
- Use the hue slider to select the base color type
- Range: 0-360° (Red → Orange → Yellow → Green → Blue → Purple → Red)
📊 Visual Reference Bar
- A thin color bar displays:
White → Selected Hue → Black
- Shows the full spectrum for your chosen hue
- Position indicator shows where your current color sits
- A thin color bar displays:
🎛️ Fine-tune Color Properties
- Saturation Slider: Adjust color intensity (0% = Gray ↔ 100% = Vivid)
- Lightness Slider: Adjust brightness (0% = Black ↔ 100% = White)
- Opacity Slider: Control transparency (optional)
📍 Real-time Feedback
- Position indicator moves on the color bar as you adjust sliders
- Live color preview updates instantly
- RGB and HEX values displayed
💡 Example Workflow
Step 1: "I want a blue color" → Move hue slider to ~240°
Step 2: Color bar shows [White ████ Blue ████ Black]
Step 3: "Make it more vivid" → Increase saturation to 80%
Step 4: "Make it lighter" → Increase lightness to 70%
Step 5: Position indicator shows exactly where your color is: [White ██●█ Blue ████ Black]
Result: Beautiful light blue color! 🎉
🎨 Color Variants
- 2D Color Area (optional): Interactive canvas for selecting saturation and lightness simultaneously
- Individual Sliders (default): Separate controls for precise adjustment
- Simple Mode: Hue-only selection for quick color changes
- Random Mode: Generate colors within pastel or vibrant ranges
🚀 Demo
📦 Installation
From npm (Recommended)
npm install @marcosfreitas/pastel-color-picker
Peer Dependencies
npm install react react-dom @radix-ui/react-dialog @radix-ui/react-slider lucide-react clsx
🎯 Quick Start
import { ColorPicker, ColorValue } from '@marcosfreitas/pastel-color-picker';
function App() {
const [color, setColor] = useState<ColorValue>();
return (
<ColorPicker
value={color}
onChange={setColor}
variant="button"
isPastel={true}
showAlpha={true}
/>
);
}
🔧 API Reference
ColorPickerProps
Prop | Type | Default | Description |
---|---|---|---|
value |
ColorValue |
black (#000000) |
Current color value |
onChange |
(color: ColorValue) => void |
- | Callback when color changes |
variant |
'circles' | 'button' | 'random' | 'simple' |
'button' |
Presentation variant |
isPastel |
boolean |
true |
Whether to use pastel colors |
showAlpha |
boolean |
true |
Whether to show alpha channel controls |
showColorArea |
boolean |
false |
Whether to show 2D color area instead of individual sliders |
hideSliders |
boolean |
false |
Whether to hide all slider controls in dialogs |
presetColors |
string[] |
- | Custom preset colors (hex values) |
className |
string |
- | Custom CSS class |
size |
'sm' | 'md' | 'lg' |
'md' |
Size variant |
disabled |
boolean |
false |
Disabled state |
showPresets |
boolean |
true |
Show preset colors in dialog |
showIcon |
boolean |
true |
Whether to show icons in button variants |
label |
string |
- | Label text to display with the button/random/simple variants |
ColorValue Interface
interface ColorValue {
hexa: string; // Hex color (#FF0000)
rgba: { r: number; g: number; b: number; a: number }; // RGBA values
hsva: { h: number; s: number; v: number; a: number }; // HSVA values
}
🎨 Variants
Button Variant (Default)
Displays a colored button that opens a full-featured color picker dialog.
<ColorPicker variant="button" size="md" />
Circles Variant
Shows preset color circles with an option to open the full picker.
<ColorPicker
variant="circles"
presetColors={['#FF6B6B', '#4ECDC4', '#45B7D1']}
/>
Simple Variant
A simplified version with only hue selection.
<ColorPicker variant="simple" />
Random Variant
Generates random colors with a colored bottom border indicator.
<ColorPicker variant="random" isPastel={true} />
🌈 Color Modes
Pastel Colors
When isPastel={true}
:
- Saturation: 70-100%
- Lightness: 75-90%
- Perfect for soft, elegant designs
Vibrant Colors
When isPastel={false}
:
- Saturation: 50-100%
- Lightness: 40-80%
- Great for bold, energetic designs
🎯 Advanced Usage
Custom Theme Integration
function ThemeColorPicker() {
const [themeColor, setThemeColor] = useState<ColorValue>();
const handleColorChange = (color: ColorValue) => {
setThemeColor(color);
// Update CSS custom properties
document.documentElement.style.setProperty('--theme-color', color.hexa);
document.documentElement.style.setProperty(
'--theme-color-rgb',
`${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}`
);
};
return (
<ColorPicker
variant="button"
value={themeColor}
onChange={handleColorChange}
showAlpha={false}
/>
);
}
Brand Color Selector
const brandColors = [
'#1a73e8', '#ea4335', '#fbbc04', '#34a853',
'#9aa0a6', '#5f6368', '#202124', '#fff'
];
<ColorPicker
variant="circles"
presetColors={brandColors}
showPresets={false}
isPastel={false}
/>
Minimalist Color Picker
function MinimalistPicker() {
const [color, setColor] = useState<ColorValue>();
return (
<ColorPicker
variant="button"
value={color}
onChange={setColor}
hideSliders={true}
showColorArea={true}
showPresets={false}
label="Pick Color"
/>
);
}
Transparency-Aware Color Picker
function TransparencyPicker() {
const [bgColor, setBgColor] = useState<ColorValue>();
return (
<ColorPicker
variant="button"
value={bgColor}
onChange={setBgColor}
showAlpha={true}
showColorArea={true}
hideSliders={false}
/>
);
}
Form Integration
function ColorForm() {
const [formData, setFormData] = useState({
backgroundColor: null as ColorValue | null,
textColor: null as ColorValue | null,
});
return (
<form>
<div>
<label>Background Color</label>
<ColorPicker
value={formData.backgroundColor}
onChange={(color) => setFormData(prev => ({
...prev,
backgroundColor: color
}))}
/>
</div>
<div>
<label>Text Color</label>
<ColorPicker
value={formData.textColor}
onChange={(color) => setFormData(prev => ({
...prev,
textColor: color
}))}
showAlpha={false}
/>
</div>
</form>
);
}
🎨 Styling
The component uses Tailwind CSS for styling. Make sure to include the required CSS variables:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96%;
--secondary-foreground: 222.2 84% 4.9%;
--muted: 210 40% 96%;
--muted-foreground: 215.4 16.3% 46.9%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
♿ Accessibility
- Full keyboard navigation
- ARIA labels and descriptions
- Screen reader support
- Focus management
- High contrast mode support
🌐 Browser Support
- Chrome/Edge: 88+
- Firefox: 78+
- Safari: 14+
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
📝 License
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with Radix UI primitives
- Styled with Tailwind CSS
- Icons from Lucide React
- Inspired by modern design systems
Made with ❤️ by Ordinary Link
Usage Options
This library provides three different usage patterns to fit different needs:
Option 1: Self-Contained (Recommended for Quick Setup)
import { ColorPicker } from '@marcosfreitas/pastel-color-picker';
import '@marcosfreitas/pastel-color-picker/style.css';
// Works out of the box - no Tailwind config needed
Option 2: Headless (Best for Tailwind v4 Projects)
import { ColorPicker } from '@marcosfreitas/pastel-color-picker/headless';
// No CSS import needed - uses your Tailwind config
// Ensure your tailwind.config includes the package in content:
// content: ['./node_modules/@marcosfreitas/pastel-color-picker/**/*.js']
What is "Headless"?
- ✅ Same components & functionality as the regular version
- ✅ Zero bundled CSS - uses your project's Tailwind utilities
- ✅ Smaller bundle size (~35KB CSS savings)
- ✅ Perfect integration with existing Tailwind v4 projects
- ⚠️ Requires your project to have all necessary Tailwind utilities
Best for:
- Projects already using Tailwind CSS v4
- Teams with custom design systems
- Performance-critical applications
- When you want full control over styling
Option 3: Source Import (Maximum Customization)
import { ColorPicker } from '@marcosfreitas/pastel-color-picker/src';
// Direct source import - full control over styling
Which option to choose:
Scenario | Use This | Why |
---|---|---|
🚀 Quick prototyping | Self-contained | Works immediately, no setup |
⚡ Existing Tailwind v4 project | Headless | Avoids duplicate CSS, smaller bundle |
🎨 Custom design system | Headless or Source | Full control over styling |
🔧 Need to modify components | Source | Direct access to component code |
📦 Bundle size matters | Headless | ~35KB CSS savings |
Usage
import { ColorPicker } from '@marcosfreitas/pastel-color-picker';
import '@marcosfreitas/pastel-color-picker/style.css'; // Don't forget this!
function App() {
const [color, setColor] = useState('#ff6b6b');
return (
<ColorPicker
value={color}
onChange={setColor}
variant="circles"
/>
);
}
🔧 Headless Version Setup
For the headless version, ensure your tailwind.config.js
includes:
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx}',
'./node_modules/@marcosfreitas/pastel-color-picker/**/*.js', // Add this!
],
// ... rest of your config
}
Troubleshooting Missing Classes
If you see unstyled components with the headless version:
- Check content path: Ensure the package is included in your Tailwind content
- Verify utilities: Make sure your project has these utilities:
size-4
,ring-ring/50
,outline-hidden
,focus-visible:ring-4
- Add missing utilities: Add them to your CSS if needed:
@layer utilities {
.size-4 { width: 1rem; height: 1rem; }
.ring-ring\/50 { --tw-ring-color: oklch(var(--ring) / 0.5); }
.outline-hidden { outline: 2px solid transparent; }
}