Skip to main content

Usage

import { ColorSwatch } from '@kivora/react';

<ColorSwatch color="#3b82f6" aria-label="Blue" />

Examples

Basic Swatch

<ColorSwatch color="#3b82f6" aria-label="Blue" />

Clickable Swatch

function ColorPicker() {
  const [selected, setSelected] = useState('#3b82f6');

  return (
    <ColorSwatch 
      color="#3b82f6" 
      onClick={() => setSelected('#3b82f6')}
      aria-label="Select blue"
    />
  );
}

Sizes

<ColorSwatch color="#ef4444" size="xs" aria-label="Red" />

Read-Only

<ColorSwatch color="#8b5cf6" size="md" readOnly />
Renders as a <span> with no interaction states.

Color Palette

function ColorPalette() {
  const [selected, setSelected] = useState('#3b82f6');
  
  const colors = [
    { value: '#ef4444', name: 'Red' },
    { value: '#f59e0b', name: 'Orange' },
    { value: '#10b981', name: 'Green' },
    { value: '#3b82f6', name: 'Blue' },
    { value: '#8b5cf6', name: 'Purple' },
    { value: '#ec4899', name: 'Pink' },
  ];

  return (
    <div className="flex gap-2">
      {colors.map(color => (
        <ColorSwatch
          key={color.value}
          color={color.value}
          size="md"
          onClick={() => setSelected(color.value)}
          aria-label={color.name}
          className={selected === color.value ? 'ring-2 ring-offset-2' : ''}
        />
      ))}
    </div>
  );
}

Theme Color Grid

const themeColors = {
  primary: ['#eff6ff', '#dbeafe', '#bfdbfe', '#93c5fd', '#60a5fa', '#3b82f6'],
  success: ['#f0fdf4', '#dcfce7', '#bbf7d0', '#86efac', '#4ade80', '#22c55e'],
  warning: ['#fef3c7', '#fde68a', '#fcd34d', '#fbbf24', '#f59e0b', '#d97706'],
  error: ['#fee2e2', '#fecaca', '#fca5a5', '#f87171', '#ef4444', '#dc2626'],
};

function ThemeColorGrid() {
  return (
    <div className="space-y-4">
      {Object.entries(themeColors).map(([name, shades]) => (
        <div key={name}>
          <h4 className="text-sm font-medium mb-2 capitalize">{name}</h4>
          <div className="flex gap-2">
            {shades.map((color, i) => (
              <ColorSwatch
                key={color}
                color={color}
                size="lg"
                aria-label={`${name} ${i + 1}`}
              />
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

Color Picker with Preview

function ColorPickerWithPreview() {
  const [color, setColor] = useState('#3b82f6');

  const presetColors = [
    '#ef4444', '#f59e0b', '#10b981', '#3b82f6', 
    '#8b5cf6', '#ec4899', '#6366f1', '#14b8a6',
  ];

  return (
    <div className="space-y-4">
      <div className="flex items-center gap-3">
        <ColorSwatch color={color} size="lg" readOnly />
        <div>
          <p className="text-sm font-medium">Selected Color</p>
          <p className="text-xs text-muted-foreground">{color}</p>
        </div>
      </div>
      
      <div className="grid grid-cols-8 gap-2">
        {presetColors.map(c => (
          <ColorSwatch
            key={c}
            color={c}
            size="md"
            onClick={() => setColor(c)}
            aria-label={c}
            className={color === c ? 'ring-2 ring-primary' : ''}
          />
        ))}
      </div>
    </div>
  );
}

Gradient Swatches

<div className="flex gap-2">
  <ColorSwatch 
    color="transparent"
    style={{ 
      background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
    }}
    size="lg"
    aria-label="Purple gradient"
  />
  <ColorSwatch 
    color="transparent"
    style={{ 
      background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)'
    }}
    size="lg"
    aria-label="Pink gradient"
  />
</div>

Props

color
string
required
CSS color value (hex, rgb, hsl, named color, etc.)
size
'xs' | 'sm' | 'md' | 'lg'
default:"md"
Swatch size
readOnly
boolean
default:false
Render as non-interactive span (no hover/focus effects)
onClick
() => void
Click handler (only works when readOnly is false)
className
string
Additional CSS classes
style
React.CSSProperties
Inline styles (useful for gradients)
ColorSwatch also accepts all standard HTML <button> attributes (when interactive) or <span> attributes (when read-only).

Accessibility

  • Interactive swatches use semantic <button> element
  • Requires aria-label to describe the color for screen readers
  • Keyboard accessible with focus ring
  • Focus ring offset for clear visual indication
  • Read-only swatches render as <span> for non-interactive display

Best Practices

  • Always provide descriptive aria-label for accessibility
  • Use appropriate size based on context (smaller for palettes, larger for pickers)
  • Consider adding visual selection indicator (ring, checkmark, etc.)
  • Group related colors together
  • Ensure sufficient contrast between swatch and background
  • Use read-only mode for display-only scenarios

Build docs developers (and LLMs) love