Color Picker Input — Free HTML CSS JS Snippet

Color Picker Input · Forms · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

PRESETS array of hex colours rendered as clickable swatches
Swatch click calls pick(colour) — updates hex input and preview bar
Hex input oninput updates preview bar in real time
Native <input type="color"> hidden, triggered by eyedropper button click
color input "input" event syncs native picker selection to hex input
Live preview bar spans full card width — immediate colour feedback
Swatch .active border ring shows currently selected preset
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons
Live split-pane editor — preview updates as you type

About this UI Snippet

Color Picker Input — Preset Swatches, Hex Input Sync, Opacity Slider & Native Picker

Screenshot of the Color Picker Input snippet rendered live

A colour picker input is a specialised form field that lets users select a colour through multiple interaction methods: clicking a preset swatch, typing a hex code directly, or opening the native OS colour picker via an eyedropper button. For a hue wheel instead, see the color wheel picker; for product variants, the color swatch selector. This snippet implements all three methods in a unified card component with a live preview bar, an opacity slider, and full two-way synchronisation between every input method.

The PRESETS swatch array

The PRESETS array contains 10 hex colour values covering the most common brand palette needs: reds, oranges, yellows, greens, blues, indigos, purples, pinks, and neutrals. The swatch rendering loop uses PRESETS.forEach(c => { const s = document.createElement('div'); s.className = 'sw'; s.style.background = c; s.onclick = () => { ... }; row.appendChild(s); }). When a swatch is clicked, it marks itself with the .active class (adding a dark border ring), updates the hex input value, and calls applyColor(hex) to update the preview bar.

The hex input with live validation

The hex input is prefixed by a # hash span (purely decorative, the hash is not part of the input value). The fromHex(v) function validates the input using /^[0-9a-fA-F]{6}$/.test(v) and only calls applyColor() when exactly 6 valid hex characters are present. This prevents the preview from flashing during typing. The input uses text-transform: uppercase in CSS to display hex values in the standard uppercase format.

The hidden native colour picker

A real <input type="color"> element is rendered at 0 width and height with opacity: 0; pointer-events: none so it is invisible but fully functional. The eyedropper button's onclick calls document.getElementById('native').click() to programmatically open the OS colour picker. When the user selects a colour in the OS picker, the oninput="fromNative(this.value)" handler fires, strips the leading hash, and syncs the hex input and preview bar. This technique opens the native picker without any visible input element in the UI.

The opacity slider with gradient track

The opacity range input controls a separate opacity variable. The setOpacity(v) function converts the 0–100 range value to a 0–1 decimal for the rgba() colour in the preview. The slider track is updated dynamically: linear-gradient(to right, #hex opacity%, #e2e8f0 opacity%) creates a visual fill effect showing how much of the track corresponds to the current opacity value.

The applyColor() function

applyColor(hex) is the single function that all three input methods call. It parses the 6-character hex into r, g, b integer values using parseInt(hex.slice(0,2), 16) and constructs an rgba(r,g,b,opacity/100) string applied to the preview bar's background. This single-source-of-truth approach ensures the preview is always consistent regardless of which input method was used.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out how the eyedropper button and the hidden color input actually cooperate just by staring at it. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the native input type color element is rendered at zero size with pointer-events none rather than just hidden, and how document.getElementById('native').click() manages to open the OS picker from a completely different-looking button. The same assistant can help optimize it — for instance asking whether re-querying the range input with document.querySelector on every applyColor call is wasteful compared to caching the reference once. It's also useful for extending the component: ask it to add an eyedropper using the real EyeDropper API where supported, support an alpha-aware hex8 format instead of a separate opacity slider, or persist the last-picked color to localStorage between visits. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a color picker input field in plain HTML, CSS, and JavaScript combining preset swatches, a hex text field, a hidden native color input, and an opacity slider — no color-picker libraries.

Requirements:
- A row of clickable preset swatches generated from a PRESETS array of hex strings (not hardcoded HTML per swatch), where clicking one marks itself active with a visible ring and updates every other control to match.
- A hex text input prefixed with a purely decorative "#" label, validating with a strict six-character hex regex, only applying the color once exactly six valid hex characters are present so the preview never flashes on incomplete input.
- A real input type="color" element rendered at zero width and height with pointer-events disabled so it is invisible, triggered by a separate visible eyedropper-icon button that calls its .click() method to open the OS native color picker without showing the raw input in the layout.
- Two-way sync so picking a color in the native picker updates the hex field and vice versa, both funneling through one single source-of-truth function that applies the current color to a preview bar.
- An opacity range slider (0-100) that combines with the current hex color to produce an rgba() value applied to the preview bar's background, and that also repaints the slider's own track with a linear-gradient so the filled portion visually matches the current opacity percentage.
- Keep a single applyColor function as the only place that writes to the preview bar's background, called by all three input methods (swatch click, hex typing, native picker) so they can never fall out of sync.

Step by step

How to Use

  1. 1
    Click preset swatches to select a colourClick any of the 10 preset colour swatches below the hex input. The clicked swatch gets a dark active border ring, the hex input updates with the swatch's hex code, and the preview bar at the top of the card immediately changes to the selected colour.
  2. 2
    Type a hex code directly into the inputClick the hex input field and type a 6-character hex code like 3B82F6 (without the # prefix — the # is shown as a prefix label). The preview bar updates as soon as you type a valid 6-character hex value. The input validates with /^[0-9a-fA-F]{6}$/ before applying.
  3. 3
    Open the OS native colour picker via the eyedropper buttonClick the eyedropper icon button on the right side of the hex input row. This programmatically triggers a hidden <input type='color'> element, opening your operating system's native colour picker. When you select a colour and close the picker, the hex input and preview bar update to match your selection.
  4. 4
    Adjust the opacity sliderDrag the Opacity range slider to change transparency from 0% (fully transparent) to 100% (fully opaque). The preview bar background uses rgba() so it shows the colour at the selected opacity over the white card background. The slider track fills with the current colour to show the full opacity gradient.
  5. 5
    Customise the PRESETS array with your brand paletteIn the JS panel, replace the PRESETS array values with your own brand colour hex codes. The swatches are generated dynamically from this array, so adding, removing, or reordering entries automatically updates the rendered swatch row without any HTML changes.
  6. 6
    Read the selected colour value for form submission or CSS variable updatesAfter colour selection, read hexInp.value for the hex code (6 characters, no hash). For CSS custom property updates: document.documentElement.style.setProperty('--accent-color', '#' + hexInp.value). For form submission, include it as a hidden input or append it to your FormData object before submitting.

Real-world uses

Common Use Cases

Theme and brand colour customisation panels
Use in user-facing settings panels where users pick an accent or primary brand colour for their workspace, dashboard, or profile. The PRESETS array provides common brand palette starting points while the hex input allows precise colour specification. The opacity slider enables setting semi-transparent overlay colours for backgrounds and decorative elements.
Profile and avatar background colour pickers
Let users personalise their profile avatar background colour, their team's colour tag, or their workspace accent colour. The preset swatches guide users toward aesthetically compatible choices while the hex input and native picker let power users enter exact brand colours. The active swatch ring clearly shows which preset is currently selected.
Design tools and canvas editors
A standard UI component in web-based design tools, no-code page builders, and canvas editors where users select fill colours, stroke colours, and text colours. The multi-input approach (swatches + hex + native picker) matches how professional tools like Figma and Canva implement their colour selection interfaces.
Learn hidden input type=color with programmatic trigger
The native colour picker is opened by programmatically clicking a hidden <input type='color'> element. This technique lets you use a custom-styled button as the trigger while still leveraging the OS native picker. Study how fromNative() syncs the picked colour back to the hex text input, demonstrating the two-way synchronisation pattern between native and custom UI elements.
Live CSS custom property overrides
On colour selection, apply the chosen colour directly to a CSS custom property: document.documentElement.style.setProperty('--brand-color', '#' + hexInp.value). Combine with CSS variables throughout your stylesheet to create a live theme preview where every branded element updates in real time as the user selects different colours.
Background and text colour contrast configurators
Use two picker instances side by side — one for background colour, one for text — and calculate the WCAG contrast ratio between the two selected colours in real time. Display a pass/fail accessibility indicator and the contrast ratio value to help users choose colour combinations that meet AA or AAA accessibility standards for their design.

Got questions?

Frequently Asked Questions

A hidden <input type='color' id='native'> element is rendered with opacity: 0; width: 0; height: 0; pointer-events: none so it is invisible but functional. The eyedropper button's onclick handler calls document.getElementById('native').click(), which programmatically opens the OS native colour picker. When the user selects a colour and the picker closes, the oninput='fromNative(this.value)' handler fires. fromNative() strips the leading # from the value, converts it to uppercase, sets hexInp.value to the stripped hex string, sets native.value to synchronise them, then calls applyColor() to update the preview bar and opacity slider track.

The fromHex(v) function checks two conditions before calling applyColor: v.length === 6 ensures the full 6-character code is entered (so the preview doesn't flash during typing of incomplete codes), and /^[0-9a-fA-F]{6}$/.test(v) ensures all characters are valid hexadecimal digits. If either check fails, the function returns early without updating the preview. When both pass, native.value is synchronised to '#' + v and applyColor(v.toUpperCase()) is called to update the preview bar.

The setOpacity(v) function stores the slider value in the opacity variable and calls applyColor(hexInp.value). Inside applyColor(hex), the function parses the hex string into r, g, b integer values using parseInt(hex.slice(0,2), 16) for each channel. It then constructs rgba(r, g, b, opacity/100) and applies it to bar.style.background. The slider track is simultaneously updated using linear-gradient(to right, #hex opacity%, #e2e8f0 opacity%) to create a visual fill effect that shows the current opacity as a proportional fill of the track.

Replace the PRESETS array with objects containing both the hex value and a name: const PRESETS = [{hex:'#ef4444',name:'Red'},{hex:'#6366f1',name:'Indigo'},...]. In the swatch-building loop, set s.style.background = c.hex, s.title = c.name (for native browser tooltip), and pass c.hex to the onclick handler's applyColor call. For a custom styled tooltip instead of the native title, add a tooltip span as a child of the swatch and show/hide it on mouseenter/mouseleave events.