<!-- ColorPicker definition -->
<template id="color-picker-template">
  <div class="preview"></div>
  <div class="palette"></div>
  <button class="reset-button">Reset</button>
  
  <style>
    /* <color-picker> element */
    :host {
      --preview-width: 300px;
      --swatch-height: calc(var(--preview-width) / 5);
      
      display: flex;
      flex-direction: column;
      width: var(--preview-width);
      margin: 0 auto;
    }
    
    :host .preview {
      width: var(--preview-width);
      height: var(--preview-width);
      background-color: #111111;
    }
    
    :host .palette {
      display: flex;
      width: 100%;
    }
    
    :host .palette > .swatch {
      flex: 1;
      height: var(--swatch-height);
    }
    
    :host .reset-button {
      margin-top: 10px;
    }
  </style>
</template>

<!-- ColorPicker usage -->
<h1>Click within a <code>ColorPicker</code>'s palette to preview a color.</h1>
<div class="grid">
  <div>
    <h2>Default palette</h2>
    <color-picker></color-picker>
    <p>The <code>ColorPicker</code> uses a bright 5-color palette if you don't specify one.</p>
  </div>
  <div>
    <h2>Palette from <a href="https://coolors.co/355070-6d597a-b56576-e56b6f-eaac8b-e5dcc5" target="_blank" rel="noreferrer noopener">Coolors</a></h2>
    <color-picker data-palette='["#355070", "#6d597a", "#b56576", "#e56b6f", "#eaac8b", "#e5dcc5"]'></color-picker>
    <p>You can pass any number of colors to use as a palette using the <code>data-palette</code> attribute.</p>
  </div>
  <div>
    <h2>Define colors any way</h2>
    <color-picker data-palette='["#1b7141", "seagreen", "rgb(71, 160, 110)", "hsl(146deg, 33%, 55%)"]'></color-picker>
    <p>Hexadecimal, named colors, <code>rgb()</code>, and <code>hsl()</code> are fair game.</p>
  </div>
</div>
body {
  text-align: center;
  line-height: 1.5;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 1.5rem;
}
class ColorPicker extends HTMLElement {
  constructor() {
    super();
    
    // Attach a shadow root to the element
    const template = document.getElementById('color-picker-template');
    const shadowRoot = this.attachShadow({ mode: 'open' });
    shadowRoot.appendChild(template.content.cloneNode(true));
    
    // Preserve method context
    this.setPreviewColor = this.setPreviewColor.bind(this);
    this.resetPreview = this.resetPreview.bind(this);
    
    // Get element references
    this.previewElement = shadowRoot.querySelector('.preview');
    this.paletteElement = shadowRoot.querySelector('.palette');
    this.resetButton = shadowRoot.querySelector('.reset-button');
    
    // Initialize palette based on data attributes, if possible
    const dataPalette = this.dataset.palette;
    const defaultPalette = [
      '#e62e25',
      '#68f312',
      '#35a3fa',
      '#f29f27',
      '#e140fe',
    ];
    const palette = dataPalette ? JSON.parse(dataPalette) : defaultPalette;
    
    // Attach palette colors
    palette.forEach(color => {
      const swatchElement = document.createElement('div');
      swatchElement.className = 'swatch';
      swatchElement.dataset.color = color;
      swatchElement.style.backgroundColor = color;
      
      this.paletteElement.appendChild(swatchElement);
    });
    
    // Add event listeners
    this.paletteElement.addEventListener('click', this.setPreviewColor);
    this.resetButton.addEventListener('click', this.resetPreview);
  }
  
  disconnectedCallback() {
    // Remove event listeners
    this.paletteElement.removeEventListener('click', this.setPreviewColor);
    this.resetButton.removeEventListener('click', this.resetPreview);
  }
  
  setPreviewColor(event) {
    const color = event.target.dataset.color;
    
    this.previewElement.style.backgroundColor = color;
  }
  
  resetPreview() {
    this.previewElement.style.removeProperty('background-color');
  }
}

window.customElements.define('color-picker', ColorPicker);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.