Skip to content

HyGradientPicker ​

Usage examples on this page are written for Lit / plain HTML (<hy-gradient-picker>). The same component ships as HyGradientPicker in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

A gradient's stops on one bar: the bar draws the gradient from its start to its end, a handle sits on each stop, and the stops are moved, added and removed on it. It edits where the stops are and how many there are; the color of a stop is chosen beside it, with whatever control fits — hy-color-picker, or a list of a design system's shades — and handed back in stops.

Using it ​

  • Click the bar where there is no handle to add a stop there, on release. It takes the color the gradient already has at that spot, so the bar looks the same, and it is selected, so the control beside it changes the new stop. A press that moves adds nothing.
  • Drag a handle to move its stop; a press near a handle grabs it, as a 24 px target would. Past a neighbor the stops re-sort; the moved stop stays selected. Escape while dragging puts the stop back.
  • Drag a handle off the bar to remove its stop: it lifts, the bar shows the gradient without it, and release removes it. Back on the bar, it stays. Delete (or Backspace) on a focused handle removes it too. Never below min-stops.
  • Keyboard on a handle: the arrows move it 1 % (Shift 10 %), Home and End take it to the ends, Page Up / Page Down 10 %. Each handle is a slider, so a screen reader hears "Stop 2 of 3" and its position (with its color's name when the stop has a label).
  • caption-selected writes the selected stop's name under its handle ("Stop 2"), for a picker whose stops are edited in a list beside it that names them the same way: the name says which row the handle is. It takes room under the bar, so nothing below moves when the selection does. Screen readers already hear the name on the handle.

Its value ​

stops is the gradient's stop list, { color, position, label? }, positions 0–1. The picker changes its own value, as a slider does, and reports it: input while a handle is dragged (and once more, with the stops put back, when a drag is canceled), change when a move is committed or a stop is added or removed, both with the sorted stops, the reason and the stop's index; select when another stop is selected. A parent that keeps the stops elsewhere writes them back. A stop added between two others takes a hex mixed from them in OKLab, as the bar is drawn; a stop at or past an end takes that end's color and name.

The bar is drawn from the inline start, so it runs right to left in a right-to-left page, and over a checkerboard, so a stop with transparency shows as transparent. It is a straight line whatever the gradient's angle: the angle is set apart (hy-angle-picker).

When to use

  • Editing the colors of a gradient and where they sit along it.

Do

  • Set min-stops to the fewest colors the gradient needs.

When not to use

  • Choosing one color: hy-color-picker.
  • A value between two ends: hy-slider, or its range mode for a span.

Accessibility: your part ​

  • Name the picker with label, or aria-label / aria-labelledby on the host.
  • Give each stop a label when its color has a name, so screen readers hear the color, not only a position.
  • Put the selected stop's color control right after the picker, so Tab reaches it next.

Examples ​

Basic usage ​

html
<hy-gradient-picker label="Banner gradient"></hy-gradient-picker>
<script>
  const picker = document.querySelector('hy-gradient-picker');
  picker.stops = [
    { color: '#3366ff', position: 0, label: 'Blue' },
    { color: '#ff6699', position: 1, label: 'Pink' },
  ];
  picker.addEventListener('change', (e) => console.log(e.detail.stops));
</script>

With a color control for the selected stop ​

html
<hy-gradient-picker label="Banner gradient"></hy-gradient-picker>
<hy-color-picker label="Selected color"></hy-color-picker>
<script>
  const picker = document.querySelector('hy-gradient-picker');
  const color = document.querySelector('hy-color-picker');
  picker.stops = [
    { color: '#3366ff', position: 0 },
    { color: '#ff6699', position: 1 },
  ];
  const show = () => (color.value = picker.stops[picker.selected].color);
  picker.addEventListener('select', show);
  picker.addEventListener('change', show);
  color.addEventListener('change', (e) => {
    picker.stops = picker.stops.map((s, i) =>
      i === picker.selected ? { ...s, color: e.detail.value } : s,
    );
  });
</script>

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
stops—GradientPickerStop[][]The stops, { color, position, label? }, positions 0–1. Shown sorted by position.
selectedselectednumber0The index of the selected stop in stops.
minStopsmin-stopsnumber2The fewest stops the picker keeps: Delete stops there.
labellabelstring''The picker's visible name.
helperTexthelper-textstring''A short hint below the bar.
sizesize'small' | 'medium' | 'large''medium'Size of the bar, its handles and the row they sit in.
disableddisabledbooleanfalseDisables the picker: nothing moves, nothing is added or removed.
localelocalestring | undefined—BCP-47 locale for the positions read out. Unset, the nearest lang, else the browser's.
stopLabelstop-labelstring'Stop {index} of {count}'A handle's name: {index} and {count} are the stop's number and how many there are.
stopValueTextstop-value-textstring'{name} at {position}'A named stop's position as read out: {name} is its label, {position} its percentage.
captionSelectedcaption-selectedbooleanfalseWrites the selected stop's name under its handle, taking room under the bar for it.
stopCaptionTextstop-caption-textstring'Stop {index}'The name under the selected handle: {index} and {count} as in stopLabel.
autofocusautofocusbooleanfalseFocuses the selected handle on first connect, and marks it for an overlay's discovery.

Events ​

EventDetailDescription
input—Fires while a handle is dragged, and with the stops put back when a drag is canceled. Detail: GradientPickerChangeDetail
change—Fires when a move is committed or a stop is added or removed. Detail: GradientPickerChangeDetail
select—Fires when another stop is selected. Detail: GradientPickerSelectDetail

CSS Parts ​

PartDescription
baseThe outer wrapper (label, bar, helper text)
labelThe label
barThe row holding the track and its handles
trackThe bar showing the gradient
handleA stop's handle
captionThe selected stop's name under its handle (caption-selected)
helper-textThe helper text

CSS Custom Properties ​

The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.

PropertyDefaultDescription
--hy-gradient-picker-control-height-smvar(--hy-control-height-sm)Height of the row the bar sits in, at size small
--hy-gradient-picker-control-height-mdvar(--hy-control-height-md)Height of the row the bar sits in, at size medium
--hy-gradient-picker-control-height-lgvar(--hy-control-height-lg)Height of the row the bar sits in, at size large
--hy-gradient-picker-track-indicator-size-smvar(--hy-indicator-size-sm)Height of the bar, at size small
--hy-gradient-picker-track-indicator-size-mdvar(--hy-indicator-size-md)Height of the bar, at size medium
--hy-gradient-picker-track-indicator-size-lgvar(--hy-indicator-size-lg)Height of the bar, at size large
--hy-gradient-picker-handle-ornament-pelletvar(--hy-ornament-pellet)Diameter of a handle, at size small
--hy-gradient-picker-handle-ornament-knobvar(--hy-ornament-knob)Diameter of a handle, at size medium
--hy-gradient-picker-handle-control-height-xsvar(--hy-control-height-xs)Diameter of a handle, at size large
--hy-gradient-picker-handle-radius-pill-circlevar(--hy-radius-pill-circle)Corner of a handle (round)
--hy-gradient-picker-track-radius-pill-mdvar(--hy-radius-pill-md)Corner of the bar
--hy-gradient-picker-track-border-default-restvar(--hy-border-default-rest)Edge of the bar
--hy-gradient-picker-handle-background-surface-basevar(--hy-background-surface-base)Ring around a handle's color
--hy-gradient-picker-handle-border-default-restvar(--hy-border-default-rest)Outer edge of a handle
--hy-gradient-picker-handle-border-brand-restvar(--hy-border-brand-rest)Ring of the selected handle
--hy-gradient-picker-handle-shadow-elevation-2var(--hy-shadow-elevation-2)Shadow under a handle
--hy-gradient-picker-foreground-default-restvar(--hy-foreground-default-rest)Label color
--hy-gradient-picker-helper-foreground-subtle-restvar(--hy-foreground-subtle-rest)Helper text color
--hy-gradient-picker-background-neutral-disabledvar(--hy-background-neutral-disabled)The bar's veil and the handles when disabled
--hy-gradient-picker-border-default-disabledvar(--hy-border-default-disabled)Edges when disabled
--hy-gradient-picker-gap-form-smvar(--hy-gap-form-sm)Gap between the label, the bar and the helper text
--hy-gradient-picker-stroke-smvar(--hy-stroke-sm)Width of the bar's edge and a handle's outer edge
--hy-gradient-picker-stroke-mdvar(--hy-stroke-md)Width of a handle's ring
--hy-gradient-picker-motion-transition-hover-durationvar(--hy-motion-transition-hover-duration)Transition duration for hover and selection feedback
--hy-gradient-picker-motion-transition-hover-easingvar(--hy-motion-transition-hover-easing)Transition easing for hover and selection feedback

Methods ​

focus() ​

Focuses the selected stop's handle.

blur() ​

Blurs the focused handle.

Built with Lit. Documented with VitePress.