Color Picker Rails Components

Add color selection functionality to your forms with native HTML5 color inputs, enhanced color pickers with swatches, and advanced third-party solutions. Perfect for theme customization, design tools, and user preferences.

Installation

1. Shoelace Color Picker

For advanced color picker features, you can use Shoelace's color picker component. :

<!-- Shoelace -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/components/color-picker/color-picker.js"></script>
<link
  rel="stylesheet"
  media="(prefers-color-scheme:light)"
  href="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/themes/light.css"
/>
<link
  rel="stylesheet"
  media="(prefers-color-scheme:dark)"
  href="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/themes/dark.css"
  onload="document.documentElement.classList.add('sl-theme-dark');"
/>

2. Shoelace Styling

If you want to have more neutral accent colors instead of the default blue & more rounded corners, you can use the following CSS to style the Shoelace color picker:

/* Shoelace Neutral styles */
.sl-theme-dark {
  color-scheme: dark;

  --sl-color-primary-50: var(--sl-color-neutral-50) !important;
  --sl-color-primary-100: var(--sl-color-neutral-100) !important;
  --sl-color-primary-200: var(--sl-color-neutral-200) !important;
  --sl-color-primary-300: var(--sl-color-neutral-300) !important;
  --sl-color-primary-400: var(--sl-color-neutral-400) !important;
  --sl-color-primary-500: var(--sl-color-neutral-500) !important;
  --sl-color-primary-600: var(--sl-color-neutral-600) !important;
  --sl-color-primary-700: var(--sl-color-neutral-700) !important;
  --sl-color-primary-800: var(--sl-color-neutral-800) !important;
  --sl-color-primary-900: var(--sl-color-neutral-900) !important;
  --sl-color-primary-950: var(--sl-color-neutral-950) !important;

  --sl-input-focus-ring-color: hsla(0, 0%, 81%, 0.4) !important;

  --sl-border-radius-medium: 0.5rem !important;
  --sl-border-radius-large: 0.75rem !important;
}

Shoelace Examples

Enhanced color picker

Shoelace color picker with a modern interface, color format display, and copy functionality.

Current value: #3b82f6
<%# Shoelace Color Picker %>
<%# Note: This requires Shoelace %>
<div class="space-y-4">
  <div class="flex flex-col items-center gap-2">
    <sl-color-picker
      label="Brand Color"
      value="#3b82f6"
      format="hex"
      size="medium"
      id="enhanced-picker"
    ></sl-color-picker>
  </div>

  <div class="flex justify-center items-center gap-3 text-sm">
    <span class="text-neutral-600 dark:text-neutral-400">Current value:</span>
    <code class="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded font-mono text-xs" id="enhanced-value">#3b82f6</code>
  </div>
</div>

<script>
  // Handle color picker changes
  const enhancedPicker = document.getElementById('enhanced-picker');
  const enhancedValue = document.getElementById('enhanced-value');
  const copyButton = document.getElementById('copy-color');

  enhancedPicker.addEventListener('sl-change', function(e) {
    enhancedValue.textContent = e.target.value;
  });

</script>

Color picker with opacity

Advanced color picker with alpha channel support for transparency control.

Hex (with alpha): #f5a623ff
RGBA: rgba(245, 166, 35, 1)

Preview:

<%# Shoelace Color Picker with Opacity/Alpha Channel %>
<div class="space-y-4">
  <div class="flex flex-col items-center gap-2">
    <sl-color-picker
      label="Background Color"
      value="#f5a623ff"
      opacity
      format="hex"
      no-format-toggle
      size="medium"
      id="opacity-picker"
    ></sl-color-picker>
  </div>

  <div class="flex flex-col gap-2">
    <div class="flex items-center gap-3 text-sm">
      <span class="text-neutral-600 dark:text-neutral-400">Hex (with alpha):</span>
      <code class="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded font-mono text-xs" id="hex-alpha-value">#f5a623ff</code>
    </div>

    <div class="flex items-center gap-3 text-sm">
      <span class="text-neutral-600 dark:text-neutral-400">RGBA:</span>
      <code class="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded font-mono text-xs" id="rgba-value">rgba(245, 166, 35, 1)</code>
    </div>
  </div>

  <%# Preview with transparency %>
  <div class="space-y-2">
    <p class="text-sm font-medium text-neutral-700 dark:text-neutral-300 text-center">Preview:</p>
    <div class="relative h-24 rounded-lg overflow-hidden outline-1 -outline-offset-1 outline-black/15 dark:outline-white/20">
      <%# Checkerboard background to show transparency %>
      <div class="absolute inset-0 checkerboard-bg opacity-20"></div>
      <div
        class="absolute inset-0"
        id="color-preview"
        style="background-color: #f5a623ff"
      ></div>
    </div>
  </div>
</div>

<script>
  // Handle opacity picker changes
  const opacityPicker = document.getElementById('opacity-picker');
  const hexAlphaValue = document.getElementById('hex-alpha-value');
  const rgbaValue = document.getElementById('rgba-value');
  const colorPreview = document.getElementById('color-preview');

  opacityPicker.addEventListener('sl-change', function(e) {
    const color = e.target.value;
    hexAlphaValue.textContent = color;

    // Convert to RGBA for display
    const r = parseInt(color.slice(1, 3), 16);
    const g = parseInt(color.slice(3, 5), 16);
    const b = parseInt(color.slice(5, 7), 16);
    const a = color.length > 7 ? (parseInt(color.slice(7, 9), 16) / 255).toFixed(2) : '1';

    rgbaValue.textContent = `rgba(${r}, ${g}, ${b}, ${a})`;
    colorPreview.style.backgroundColor = color;
  });
</script>

<style>
  /* Checkerboard pattern for transparency background */
  .checkerboard-bg {
    background-image:
      linear-gradient(45deg, #e5e7eb 25%, transparent 25%),
      linear-gradient(-45deg, #e5e7eb 25%, transparent 25%),
      linear-gradient(45deg, transparent 75%, #e5e7eb 75%),
      linear-gradient(-45deg, transparent 75%, #e5e7eb 75%);
    background-size: 20px 20px;
    background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
  }

  /* Dark mode checkerboard */
  .dark .checkerboard-bg {
    background-image:
      linear-gradient(45deg, #374151 25%, transparent 25%),
      linear-gradient(-45deg, #374151 25%, transparent 25%),
      linear-gradient(45deg, transparent 75%, #374151 75%),
      linear-gradient(-45deg, transparent 75%, #374151 75%);
  }
</style>

Color format variations

Color pickers configured for different color format outputs: HEX, RGB, HSL, and HSV.

Choose the output format that best suits your needs

Output:
#4a90e2
Output:
rgb(80, 227, 194)
Output:
hsl(290, 87%, 47%)
Output:
hsv(55, 89%, 97%)
<%# Shoelace Color picker with format variations %>
<div class="space-y-6">
  <p class="text-sm text-neutral-500 dark:text-neutral-400 text-center">
    Choose the output format that best suits your needs
  </p>

  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
    <%# HEX Format %>
    <div class="space-y-3">
      <div class="flex flex-col items-center">
        <sl-color-picker
          label="HEX Format"
          format="hex"
          value="#4a90e2"
          size="small"
          id="hex-picker"
        ></sl-color-picker>
      </div>
      <div class="text-center">
        <div class="text-xs text-neutral-500 dark:text-neutral-400 mb-1">Output:</div>
        <code class="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded font-mono text-xs text-neutral-700 dark:text-neutral-300" id="hex-output">#4a90e2</code>
      </div>
    </div>

    <%# RGB Format %>
    <div class="space-y-3">
      <div class="flex flex-col items-center">
        <sl-color-picker
          label="RGB Format"
          format="rgb"
          value="rgb(80, 227, 194)"
          size="small"
          id="rgb-picker"
        ></sl-color-picker>
      </div>
      <div class="text-center">
        <div class="text-xs text-neutral-500 dark:text-neutral-400 mb-1">Output:</div>
        <code class="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded font-mono text-xs text-neutral-700 dark:text-neutral-300" id="rgb-output">rgb(80, 227, 194)</code>
      </div>
    </div>

    <%# HSL Format %>
    <div class="space-y-3">
      <div class="flex flex-col items-center">
        <sl-color-picker
          label="HSL Format"
          format="hsl"
          value="hsl(290, 87%, 47%)"
          size="small"
          id="hsl-picker"
        ></sl-color-picker>
      </div>
      <div class="text-center">
        <div class="text-xs text-neutral-500 dark:text-neutral-400 mb-1">Output:</div>
        <code class="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded font-mono text-xs text-neutral-700 dark:text-neutral-300" id="hsl-output">hsl(290, 87%, 47%)</code>
      </div>
    </div>

    <%# HSV Format %>
    <div class="space-y-3">
      <div class="flex flex-col items-center">
        <sl-color-picker
          label="HSV Format"
          format="hsv"
          value="hsv(55, 89%, 97%)"
          size="small"
          id="hsv-picker"
        ></sl-color-picker>
      </div>
      <div class="text-center">
        <div class="text-xs text-neutral-500 dark:text-neutral-400 mb-1">Output:</div>
        <code class="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded font-mono text-xs text-neutral-700 dark:text-neutral-300" id="hsv-output">hsv(55, 89%, 97%)</code>
      </div>
    </div>
  </div>
</div>

<script>
  // Update output displays for each format
  ['hex', 'rgb', 'hsl', 'hsv'].forEach(format => {
    const picker = document.getElementById(`${format}-picker`);
    const output = document.getElementById(`${format}-output`);

    picker.addEventListener('sl-change', function(e) {
      output.textContent = e.target.value;
    });
  });
</script>

Color picker with custom palette

Enhanced color picker with a custom color palette for consistent brand colors.

Brand Palette

Neutrals

Accents

Selected Color:
#4a5568
<%# Shoelace Color Picker with Custom Brand Palette %>
<div class="space-y-6">
  <div class="flex flex-col items-center">
    <sl-color-picker
      label="Brand Color"
      value="#4a5568"
      swatches="#1a202c; #2d3748; #4a5568; #718096; #a0aec0; #cbd5e0; #e2e8f0; #f7fafc; #fed7d7; #feb2b2; #fc8181; #f56565; #e53e3e; #c53030; #9b2c2c; #742a2a"
      size="medium"
      id="brand-picker"
    ></sl-color-picker>
  </div>

  <div class="space-y-4">
    <p class="text-sm font-medium text-neutral-600 dark:text-neutral-400 text-center">Brand Palette</p>

    <div class="space-y-4">
      <%# Neutral Colors %>
      <div class="space-y-2">
        <p class="text-xs text-neutral-500 dark:text-neutral-400 uppercase tracking-wide text-center">Neutrals</p>
        <div class="flex justify-center gap-2 flex-wrap">
          <button type="button" data-color="#1a202c" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #1a202c" title="Gray 900"></button>
          <button type="button" data-color="#2d3748" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #2d3748" title="Gray 800"></button>
          <button type="button" data-color="#4a5568" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #4a5568" title="Gray 700"></button>
          <button type="button" data-color="#718096" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #718096" title="Gray 500"></button>
          <button type="button" data-color="#a0aec0" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #a0aec0" title="Gray 400"></button>
          <button type="button" data-color="#cbd5e0" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #cbd5e0" title="Gray 300"></button>
          <button type="button" data-color="#e2e8f0" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #e2e8f0" title="Gray 200"></button>
          <button type="button" data-color="#f7fafc" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #f7fafc" title="Gray 50"></button>
        </div>
      </div>

      <%# Accent Colors %>
      <div class="space-y-2">
        <p class="text-xs text-neutral-500 dark:text-neutral-400 uppercase tracking-wide text-center">Accents</p>
        <div class="flex justify-center gap-2 flex-wrap">
          <button type="button" data-color="#fed7d7" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #fed7d7" title="Red 100"></button>
          <button type="button" data-color="#feb2b2" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #feb2b2" title="Red 200"></button>
          <button type="button" data-color="#fc8181" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #fc8181" title="Red 300"></button>
          <button type="button" data-color="#f56565" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #f56565" title="Red 400"></button>
          <button type="button" data-color="#e53e3e" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #e53e3e" title="Red 500"></button>
          <button type="button" data-color="#c53030" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #c53030" title="Red 600"></button>
          <button type="button" data-color="#9b2c2c" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #9b2c2c" title="Red 700"></button>
          <button type="button" data-color="#742a2a" class="brand-swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #742a2a" title="Red 800"></button>
        </div>
      </div>
    </div>
  </div>

  <div class="flex flex-col items-center gap-3 p-4 bg-neutral-50 dark:bg-neutral-800/50 rounded-lg border border-neutral-200 dark:border-neutral-700">
    <div class="text-sm text-center">
      <div class="text-xs text-neutral-500 dark:text-neutral-400 mb-1">Selected Color:</div>
      <code class="px-2 py-1 bg-white dark:bg-neutral-900 rounded font-mono text-xs text-neutral-700 dark:text-neutral-300" id="brand-value">#4a5568</code>
    </div>
    <button
      type="button"
      class="px-3 py-1.5 text-xs bg-white dark:bg-neutral-900 hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded border border-neutral-300 dark:border-neutral-600 text-neutral-600 dark:text-neutral-400 transition-colors"
      id="add-to-palette"
    >
      Add to Palette
    </button>
  </div>
</div>

<script>
  // Handle brand picker and swatch interactions
  const brandPicker = document.getElementById('brand-picker');
  const brandValue = document.getElementById('brand-value');
  const brandSwatches = document.querySelectorAll('.brand-swatch');
  const addButton = document.getElementById('add-to-palette');

  // Update value display
  brandPicker.addEventListener('sl-change', function(e) {
    const color = e.target.value;
    brandValue.textContent = color;
    updateBrandSwatchSelection(color);
  });

  // Handle brand swatch clicks
  brandSwatches.forEach(swatch => {
    swatch.addEventListener('click', function() {
      const color = this.dataset.color;
      brandPicker.value = color;
      brandValue.textContent = color;
      updateBrandSwatchSelection(color);
    });
  });

  function updateBrandSwatchSelection(selectedColor) {
    brandSwatches.forEach(swatch => {
      if (swatch.dataset.color.toLowerCase() === selectedColor.toLowerCase()) {
        swatch.classList.remove('ring-transparent');
        swatch.classList.add('ring-neutral-500');
      } else {
        swatch.classList.remove('ring-neutral-500');
        swatch.classList.add('ring-transparent');
      }
    });
  }

  // Add to palette (example functionality)
  addButton.addEventListener('click', function() {
    const color = brandValue.textContent;
    console.log('Adding to palette:', color);
    this.textContent = 'Added!';
    setTimeout(() => {
      this.textContent = 'Add to Palette';
    }, 2000);
  });
</script>

HTML5 Examples

Basic HTML5 color picker

A native HTML5 color input - zero dependencies, works in all modern browsers.

<div class="flex flex-col items-center gap-2">
  <label for="basic-color" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-1">
    Choose a color
  </label>
  <input
    type="color"
    name="color"
    id="basic-color"
    value="#3b82f6"
    class="size-10 rounded-lg outline-1 -outline-offset-1 outline-black/15 dark:outline-white/20 cursor-pointer hover:scale-105 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200"
  >
</div>

<style>
  /* Custom styling for the color input */
  input[type="color"] {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    border: none;
  }

  input[type="color"]::-webkit-color-swatch {
    border: none;
    border-radius: 0.5rem;
  }
</style>

Color picker with swatches

HTML5 color input with predefined color swatches using datalist. Users can pick from swatches or choose custom colors.

Pick from predefined colors or choose custom

#8b5cf6

Quick select:

<%# Color Picker with Predefined Swatches %>
<div class="space-y-4">
  <div class="mb-6 relative gap-y-1.5">
    <label for="color-with-swatches" class="block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-1">
      Theme Color
    </label>
    <div class="flex items-center gap-3">
      <input
        type="color"
        name="theme_color"
        id="color-with-swatches"
        list="predefined-colors"
        value="#8b5cf6"
        class="h-12 w-12 rounded-lg outline-1 -outline-offset-1 outline-black/15 dark:outline-white/20 cursor-pointer hover:scale-105 transition-transform"
      >
      <datalist id="predefined-colors">
        <option value="#ede9fe">Violet 100</option>
        <option value="#ddd6fe">Violet 200</option>
        <option value="#c4b5fd">Violet 300</option>
        <option value="#a78bfa">Violet 400</option>
        <option value="#8b5cf6">Violet 500</option>
        <option value="#7c3aed">Violet 600</option>
        <option value="#6d28d9">Violet 700</option>
        <option value="#5b21b6">Violet 800</option>
        <option value="#4c1d95">Violet 900</option>
      </datalist>

      <div class="text-sm">
        <p class="text-neutral-600 dark:text-neutral-400">Pick from predefined colors or choose custom</p>
        <p class="font-mono text-xs text-neutral-500" id="swatch-value">#8b5cf6</p>
      </div>
    </div>
  </div>

  <%# Visual swatches for quick selection %>
  <div class="space-y-2">
    <p class="text-sm font-medium text-neutral-700 dark:text-neutral-300">Quick select:</p>
    <div class="flex gap-2 flex-wrap justify-center">
      <button type="button" data-color="#ede9fe" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #ede9fe"></button>
      <button type="button" data-color="#ddd6fe" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #ddd6fe"></button>
      <button type="button" data-color="#c4b5fd" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #c4b5fd"></button>
      <button type="button" data-color="#a78bfa" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #a78bfa"></button>
      <button type="button" data-color="#8b5cf6" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #8b5cf6"></button>
      <button type="button" data-color="#7c3aed" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #7c3aed"></button>
      <button type="button" data-color="#6d28d9" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #6d28d9"></button>
      <button type="button" data-color="#5b21b6" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #5b21b6"></button>
      <button type="button" data-color="#4c1d95" class="swatch h-8 w-8 rounded-md border border-black/15 dark:border-white/20 hover:scale-110 transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-600 dark:focus-visible:outline-neutral-200" style="background-color: #4c1d95"></button>
    </div>
  </div>
</div>

<script>
  // Update value display
  const colorInput = document.getElementById('color-with-swatches');
  const valueDisplay = document.getElementById('swatch-value');
  const swatches = document.querySelectorAll('.swatch');

  colorInput.addEventListener('change', function(e) {
    valueDisplay.textContent = e.target.value;
    updateSwatchSelection(e.target.value);
  });

  // Handle swatch clicks
  swatches.forEach(swatch => {
    swatch.addEventListener('click', function() {
      const color = this.dataset.color;
      colorInput.value = color;
      valueDisplay.textContent = color;
      updateSwatchSelection(color);
    });
  });
</script>

<style>
  /* Custom styling for the color input */
  input[type="color"] {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    border: none;
    padding: 0;
  }

  input[type="color"]::-webkit-color-swatch-wrapper {
    padding: 0;
  }

  input[type="color"]::-webkit-color-swatch {
    border: none;
    border-radius: 0.5rem;
  }
</style>

Configuration

Color pickers can be implemented using native HTML5 inputs or enhanced with third-party libraries for additional features.

Native HTML5 Color Input

The simplest approach with zero dependencies:

<input type="color" name="color" id="color" value="#3b82f6" class="...">

With Predefined Colors

Add a datalist for quick color selection:

<input type="color" list="colors" name="theme_color" value="#8b5cf6">
<datalist id="colors">
  <option value="#8b5cf6">Purple</option>
  <option value="#3b82f6">Blue</option>
  <option value="#10b981">Green</option>
</datalist>

Shoelace Color Picker Options

Available attributes for Shoelace color picker customization:

Attribute Default Description
value #ffffff The current color value
format hex Output format: hex, rgb, hsl, or hsv
opacity false Show opacity slider for alpha channel
swatches "" Custom color swatches (semicolon-separated)
label "" Label text for the color picker
size medium Size variant: small, medium, or large

JavaScript Events

Handle color selection events:

// Native color input
document.querySelector('input[type="color"]').addEventListener('change', (e) => {
  console.log('Selected color:', e.target.value);
});

// Shoelace color picker
document.querySelector('sl-color-picker').addEventListener('sl-change', (e) => {
  console.log('Color changed:', e.target.value);
});

Accessibility

  • Keyboard Support: Native color inputs are keyboard accessible
  • Screen Readers: Use proper labels and aria-labels
  • Color Contrast: Ensure selected colors meet WCAG contrast requirements

Browser Support

  • Native HTML5: Supported in all modern browsers
  • Shoelace: Requires modern browsers with Web Components support
  • Fallback: Consider text input fallback for older browsers

Table of contents