Layr
⌘K
Ctrl K
Design Systems
AI Designer
Account
Roadmap
Sign in
Adobe Spectrum - ColorWheel
Getting started
Adobe Spectrum
Spectrum UI
Pro
Components
Autocomplete
Breadcrumbs
Button
Calendar
Checkbox
Checkbox Group
Color Area
Color Field
Color Picker
Color Slider
Color Swatch
Color Swatch Picker
Color Wheel
Combo Box
Date Field
Date Picker
Date Range Picker
Dialog
Disclosure
Disclosure Group
Drop Zone
File Trigger
Form
Grid List
Group
Link
List Box
Menu
Meter
Modal
Number Field
Popover
Progress Bar
Radio Group
Range Calendar
Search Field
Select
Slider
Switch
Table
Tabs
Tag Group
Text Field
Time Field
Toast
Toggle Button
Toggle Button Group
Toolbar
Tooltip
Tree
Virtualizer
Advanced
React Aria Components
Styling
this.updateCenter()); } updateCenter() { const rect = this.wheel.getBoundingClientRect(); this.centerX = rect.left + rect.width / 2; this.centerY = rect.top + rect.height / 2; } bindEvents() { this.wheel.addEventListener('mousedown', this.handleMouseDown.bind(this)); this.wheel.addEventListener('touchstart', this.handleTouchStart.bind(this)); this.wheel.addEventListener('keydown', this.handleKeyDown.bind(this)); this.wheel.setAttribute('tabindex', '0'); document.addEventListener('mousemove', this.handleMouseMove.bind(this)); document.addEventListener('mouseup', this.handleMouseUp.bind(this)); document.addEventListener('touchmove', this.handleTouchMove.bind(this)); document.addEventListener('touchend', this.handleTouchEnd.bind(this)); } handleMouseDown(e) { if (this.options.disabled) return; e.preventDefault(); this.startDrag(e.clientX, e.clientY); } handleTouchStart(e) { if (this.options.disabled) return; e.preventDefault(); const touch = e.touches[0]; this.startDrag(touch.clientX, touch.clientY); } handleMouseMove(e) { if (!this.isDragging) return; e.preventDefault(); this.updateFromPointer(e.clientX, e.clientY); } handleTouchMove(e) { if (!this.isDragging) return; e.preventDefault(); const touch = e.touches[0]; this.updateFromPointer(touch.clientX, touch.clientY); } handleMouseUp() { this.endDrag(); } handleTouchEnd() { this.endDrag(); } handleKeyDown(e) { if (this.options.disabled) return; let delta = 0; switch (e.key) { case 'ArrowLeft': case 'ArrowDown': delta = -5; break; case 'ArrowRight': case 'ArrowUp': delta = 5; break; case 'Home': this.setHue(0); e.preventDefault(); return; case 'End': this.setHue(360); e.preventDefault(); return; } if (delta !== 0) { this.setHue(this.hue + delta); e.preventDefault(); } } startDrag(x, y) { this.isDragging = true; this.thumb.style.cursor = 'grabbing'; this.updateCenter(); this.updateFromPointer(x, y); } endDrag() { if (!this.isDragging) return; this.isDragging = false; this.thumb.style.cursor = 'grab'; if (this.options.onChangeEnd) { this.options.onChangeEnd(this.getColorValue()); } } updateFromPointer(x, y) { const dx = x - this.centerX; const dy = y - this.centerY; const angle = Math.atan2(dy, dx); const hue = ((angle * 180 / Math.PI) + 90 + 360) % 360; this.setHue(hue); } setHue(hue) { this.hue = Math.max(0, Math.min(360, hue)); this.updateThumbPosition(); this.updateValue(); if (this.options.onChange) { this.options.onChange(this.getColorValue()); } } updateThumbPosition() { const angle = (this.hue - 90) * Math.PI / 180; const radius = (this.options.outerRadius + this.options.innerRadius) / 2; const x = Math.cos(angle) * radius; const y = Math.sin(angle) * radius; this.thumb.style.left = `${this.options.outerRadius + x}px`; this.thumb.style.top = `${this.options.outerRadius + y}px`; this.thumb.style.backgroundColor = `hsl(${this.hue}, 100%, 50%)`; } updateValue() { const colorValue = this.getColorValue(); if (this.valueElement) { this.valueElement.textContent = colorValue; } } getColorValue() { return `hsl(${Math.round(this.hue)}, 100%, 50%)`; } setDisabled(disabled) { this.options.disabled = disabled; this.wheel.classList.toggle('disabled', disabled); this.thumb.classList.toggle('disabled', disabled); } } // Initialize color wheels const colorWheel1 = new ColorWheel( document.getElementById('colorWheel1'), document.getElementById('colorThumb1'), document.getElementById('colorValue1') ); const colorWheel2 = new ColorWheel( document.getElementById('colorWheel2'), document.getElementById('colorThumb2'), document.getElementById('colorValue2'), { onChange: (value) => { document.getElementById('hueInput').value = Math.round(colorWheel2.hue); } } ); colorWheel2.setHue(120); // Hue input control document.getElementById('hueInput').addEventListener('input', (e) => { colorWheel2.setHue(parseInt(e.target.value) || 0); }); // Events demo const eventsLog = document.getElementById('eventsLog'); const colorWheel3 = new ColorWheel( document.getElementById('colorWheel3'), document.getElementById('colorThumb3'), document.getElementById('colorValue3'), { onChange: (value) => { document.getElementById('currentValue').textContent = value; eventsLog.innerHTML += `
onChange: ${value}
`; eventsLog.scrollTop = eventsLog.scrollHeight; }, onChangeEnd: (value) => { document.getElementById('finalValue').textContent = value; eventsLog.innerHTML += `
onChangeEnd: ${value}
`; eventsLog.scrollTop = eventsLog.scrollHeight; } } ); colorWheel3.setHue(240); // Disabled demo const colorWheel4 = new ColorWheel( document.getElementById('colorWheel4'), document.getElementById('colorThumb4'), null, { disabled: true } ); colorWheel4.setHue(80); document.getElementById('disableToggle').addEventListener('change', (e) => { colorWheel4.setDisabled(e.target.checked); }); // Custom labeling demo const colorWheel5 = new ColorWheel( document.getElementById('colorWheel5'), document.getElementById('colorThumb5'), document.getElementById('colorValue5') ); colorWheel5.setHue(300); // Add ARIA attributes document.querySelectorAll('.color-wheel').forEach(wheel => { wheel.setAttribute('role', 'slider'); wheel.setAttribute('aria-valuemin', '0'); wheel.setAttribute('aria-valuemax', '360'); wheel.setAttribute('aria-label', 'Hue'); }); // Update ARIA values function updateAriaValue(wheel, hue) { wheel.setAttribute('aria-valuenow', Math.round(hue)); wheel.setAttribute('aria-valuetext', `${Math.round(hue)} degrees`); } // Add to existing color wheels [colorWheel1, colorWheel2, colorWheel3, colorWheel4, colorWheel5].forEach((cw, index) => { const originalSetHue = cw.setHue.bind(cw); cw.setHue = function(hue) { originalSetHue(hue); updateAriaValue(cw.wheel, hue); }; }); ' width="100%" height="1200" frameborder="0" sandbox="allow-scripts allow-same-origin allow-popups">