JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 3
  • Score
    100M100P100Q62204F
  • License GPL-3.0

A comprehensive React color picker component with multiple variants, pastel color support, and alpha channel control

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

npm version Node.js TypeScript React

A comprehensive React color picker component with multiple variants, pastel color support, and alpha channel control. Built with Radix UI primitives and modern CSS architecture.

✨ Features

  • 🎯 Multiple Variants: Button, Circles, and Random color selection modes
  • 🌈 Pastel & Vivid 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 BEM CSS methodology

🎯 How It Works

The color picker uses the HSV (Hue, Saturation, Value) color model, which provides an intuitive way to select colors by separating color properties:

🌈 Color Theory

HSV 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
  • Value (V): Brightness (0-100%) - Black to Bright

🔄 User Selection Process

  1. 🎨 Choose Base Color (Hue)

    • Use the hue slider to select the base color type
    • Range: 0-360° (Red → Orange → Yellow → Green → Blue → Purple → Red)
  2. 📊 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
  3. 🎛️ Fine-tune Color Properties

    • Saturation Slider: Adjust color intensity (0% = Gray ↔ 100% = Vivid)
    • Value Slider: Adjust brightness (0% = Black ↔ 100% = Bright)
    • Alpha Slider: Control transparency (optional)
  4. 📍 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 brighter" → Increase value to 70%
Step 5: Position indicator shows exactly where your color is: [White ██●█ Blue ████ Black]
Result: Beautiful bright blue color! 🎉

🎨 Color Variants

  • 2D Color Area (optional): Interactive canvas for selecting saturation and value simultaneously
  • Individual Sliders (default): Separate controls for precise adjustment
  • Random Mode: Generate colors within pastel or vivid ranges

🚀 Demo

Live Demo →

📦 Installation

npm install @marcosfreitas/pastel-color-picker

Peer Dependencies

npm install react react-dom

Note: All other dependencies (Radix UI, Lucide React, etc.) are bundled with the package for optimal compatibility.

🎯 Quick Start

import { ColorPicker, ColorValue, ColorMode } from '@marcosfreitas/pastel-color-picker';
import '@marcosfreitas/pastel-color-picker/style.css';
import { useState } from 'react';

function App() {
  const [color, setColor] = useState<ColorValue>();

  return (
    <ColorPicker
      defaultColor={color}
      onColorChange={setColor}
      variant="button"
      colorMode={ColorMode.PASTEL}
      showAlpha={true}
    />
  );
}

🔧 API Reference

ColorPickerProps

Prop Type Default Description
defaultColor ColorValue first preset color Current color value
onColorChange (color: ColorValue, random?: boolean) => void - Callback when color changes
variant 'button' | 'circles' | 'random' 'button' Presentation variant
colorMode 'pastel' | 'vivid' 'pastel' Color generation mode
presets string[] pastel/vivid colors Custom preset colors (hex values)
title string 'Color Picker' Dialog title
showAlpha boolean true Whether to show alpha channel controls
showColorArea boolean false Whether to show 2D color area instead of color bar
hideSliders boolean false Whether to hide all slider controls in dialogs
showPresets boolean true Show preset colors in dialog
showHue boolean true Show hue slider
showSaturation boolean true Show saturation slider
showLightness boolean true Show lightness/value slider
showRandomButton boolean true Show random color button
className string - Custom CSS class
size 'sm' | 'md' | 'lg' 'md' Size variant
disabled boolean false Disabled state
label string - Label text to display with the button/random variants
children ReactNode - Custom content for trigger button

Event Callbacks

Callback Type Description
onColorChange (color: ColorValue, random?: boolean) => void Called when color changes
onPresetClick (color: ColorValue) => void Called when preset color is clicked
onHueChange (hue: number[]) => void Called when hue slider changes
onSaturationChange (saturation: number[]) => void Called when saturation slider changes
onLightnessChange (lightness: number[]) => void Called when lightness slider changes
onAlphaChange (alpha: number[]) => void Called when alpha slider changes

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
}

ColorMode Enum

enum ColorMode {
  PASTEL = 'pastel',
  VIVID = 'vivid'
}

🎨 Variants

Button Variant (Default)

Displays a colored button that opens a full-featured color picker dialog.

<ColorPicker 
  variant="button" 
  size="md"
  colorMode={ColorMode.PASTEL}
  onColorChange={(color) => console.log(color)}
/>

Circles Variant

Shows preset color circles with an option to open the full picker.

<ColorPicker 
  variant="circles" 
  presets={['#FF6B6B', '#4ECDC4', '#45B7D1']}
  colorMode={ColorMode.VIVID}
  onColorChange={(color) => console.log(color)}
/>

Note: The label and children props are not rendered in circles variant - it uses preset circles instead.

Random Variant

Generates random colors with a colored bottom border indicator.

<ColorPicker 
  variant="random" 
  colorMode={ColorMode.PASTEL}
  onColorChange={(color) => console.log(color)}
  label="Generate Random Color"
/>

Note: The presets prop is not used in random variant - it generates colors based on colorMode only.

🎯 Variant Comparison

Feature Button Circles Random
Dialog ✅ Full dialog ✅ Full dialog ❌ No dialog
Presets ✅ Uses presets ✅ Uses presets ❌ Ignores presets
Label/Children ✅ Renders content ❌ Uses circles only ✅ Renders content
All Sliders ✅ All controls ✅ All controls ❌ No sliders
Random Generation ✅ Via dialog ✅ Via dialog ✅ Primary function
Best For Complex selection Quick presets Inspiration

Choose your variant:

  • Button: When you need full control and all color picker features
  • Circles: When you want quick preset selection with dialog fallback
  • Random: When you want simple random color generation for creative workflows

🌈 Color Modes

Pastel Colors

When colorMode="pastel":

  • Saturation: 70-100%
  • Value: 75-90%
  • Perfect for soft, elegant designs

Vivid Colors

When colorMode="vivid":

  • Saturation: 50-100%
  • Value: 40-80%
  • Great for bold, energetic designs

🎯 Advanced Usage

Custom Theme Integration

import { ColorPicker, ColorValue, ColorMode } from '@marcosfreitas/pastel-color-picker';
import '@marcosfreitas/pastel-color-picker/style.css';

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"
      defaultColor={themeColor}
      onColorChange={handleColorChange}
      showAlpha={false}
      colorMode={ColorMode.VIVID}
    />
  );
}

Brand Color Selector

const brandColors = [
  '#1a73e8', '#ea4335', '#fbbc04', '#34a853',
  '#9aa0a6', '#5f6368', '#202124', '#fff'
];

<ColorPicker
  variant="circles"
  presets={brandColors}
  showPresets={true}
  colorMode={ColorMode.VIVID}
  onColorChange={(color) => console.log('Brand color:', color)}
/>

Minimalist Color Picker

function MinimalistPicker() {
  const [color, setColor] = useState<ColorValue>();

  return (
    <ColorPicker
      variant="button"
      defaultColor={color}
      onColorChange={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"
      defaultColor={bgColor}
      onColorChange={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
          defaultColor={formData.backgroundColor}
          onColorChange={(color) => setFormData(prev => ({
            ...prev,
            backgroundColor: color
          }))}
        />
      </div>
      
      <div>
        <label>Text Color</label>
        <ColorPicker
          defaultColor={formData.textColor}
          onColorChange={(color) => setFormData(prev => ({
            ...prev,
            textColor: color
          }))}
          showAlpha={false}
        />
      </div>
    </form>
  );
}

🎨 Styling

The component uses a modern CSS architecture with BEM methodology and scoped variables. You can customize the appearance by overriding CSS custom properties:

:root {
  --pcp-color-border: 0 0% 10%;
  --pcp-color-background: 0 0% 100%;
  --pcp-color-foreground: 222.2 84% 4.9%;
  --pcp-color-primary: 222.2 47.4% 11.2%;
  --pcp-color-primary-foreground: 210 40% 98%;
  --pcp-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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📝 License

This project is licensed under the GPL-3.0 License - see the LICENSE file for details.

🙏 Acknowledgments


Made with ❤️ by Marcos Freitas

📖 Usage Options

This library provides three different usage patterns to fit different needs:

import { ColorPicker, ColorMode } from '@marcosfreitas/pastel-color-picker';
import '@marcosfreitas/pastel-color-picker/style.css';

// Works out of the box - no additional setup needed

Option 2: Headless (Best for Tailwind v4 Projects)

import { ColorPicker, ColorMode } 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, ColorMode } 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

🚀 Complete Example

import { ColorPicker, ColorValue, ColorMode } from '@marcosfreitas/pastel-color-picker';
import '@marcosfreitas/pastel-color-picker/style.css';
import { useState } from 'react';

function App() {
  const [color, setColor] = useState<ColorValue>();

  const handleColorChange = (newColor: ColorValue, isRandom?: boolean) => {
    console.log('Color changed:', newColor);
    if (isRandom) {
      console.log('This was a random color generation!');
    }
    setColor(newColor);
  };

  return (
    <div>
      <h1>My Color Picker App</h1>
      
      <ColorPicker
        variant="circles"
        defaultColor={color}
        onColorChange={handleColorChange}
        colorMode={ColorMode.PASTEL}
        showAlpha={true}
        title="Choose Your Color"
        onPresetClick={(presetColor) => console.log('Preset clicked:', presetColor)}
      />
      
      {color && (
        <div 
          style={{ 
            width: 100, 
            height: 100, 
            backgroundColor: color.hexa,
            marginTop: 20
          }}
        >
          Selected: {color.hexa}
        </div>
      )}
    </div>
  );
}

🔧 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
};