Search topics
Colour pickers you can only drag, with no field to type
A brand colour setting's square and hue strip move only when their handles are dragged, and the chosen colour is shown as text, so nothing in the picker takes focus, says what it is set to, or lets a colour be typed.
<span class="hex">#366cd9</span> The problem
People who can't drag, and screen reader users, can't set the brand colour or find out what it is set to.
A booking app lets each business set a brand colour, which it uses for the Book now button on their booking page. The settings page draws the picker that design tools made familiar: a square that runs from white to the full colour across and from light to black down, a rainbow strip under it for the hue, and the colour's code, #366cd9, written under the strip. Beside the picker, a preview shows the booking page's button in the chosen colour. With a mouse, you grab the round handle in the square and drag it, then drag the handle on the strip. A click anywhere else on the square does nothing; only the handles move.
Press Tab and focus goes straight from the top of the settings to Save: nothing in the picker takes focus. A screen reader reads "#366cd9" as text, if it reaches it, and nothing that can change it. And someone with the brand guide open, the colour written there as a hex code, has nowhere to type it.
The handles are span elements that a script moves on pointer events, and the script listens for a press on the handles alone. To the browser, the square and the strip are pictures drawn with CSS gradients and the handles are empty spans, so it gives them no Tab stop, no keys and nothing to announce. The picker fails three criteria at once. Nothing in it can be done from the keyboard, which fails 2.1.1. The handles have no role, name or value, so a screen reader can't say there is a control here or what colour it is set to, which fails 4.1.2; the code under the strip is text, not a field. And the only way to change the colour is to drag, which fails 2.5.7. Choosing a colour doesn't need a drag: WCAG's Understanding page for 2.5.7 names a text field for the colour's value, or a click on another spot in a colour wheel, as ways to set it without dragging.
Keyboard support alone doesn't settle 2.5.7, and a field alone doesn't settle everything either. Someone on a touch screen has no arrow keys, so a square that only the keys and a drag move still fails for them. And a field is the only way in for a person who can't drag but chooses colours by eye, which is why the recommended fix below keeps both.
The brand colour is set once and then shows on every page of the business's booking site, so a person who can't set it has to ask someone else to do it for them. On a phone, the handles are small and the finger covers the colour it is choosing, which makes an exact shade hard for anyone.
4 of 10 groups affected
- No vision (affected)
- Low vision (not affected)
- Colour vision (affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (affected)
- Reach, strength (affected)
- Cognitive (not affected)
- Seizures (not affected)
- Limited manipulation Keyboard, switch and voice control users can't press and hold while moving, and nothing in the picker is in the Tab order, so the brand colour stays as it is.
- Without vision Screen reader users find no control in the picker, and the hex code, if they reach it, is a line of text they can't change.
- Limited reach and strength People with tremors can't hold a handle still on the shade they want, and the colour changes again as they let go.
- Without perception of colour People who can't tell some colours apart can't judge by eye whether the square shows their brand's blue, and have no field to type the code from their brand guide.
A scanner sees two gradients, a few empty spans and a line of text, and finds nothing wrong: none of them claims to be a control, so no rule asks them for a name or a Tab stop. The audit's keyboard check finds controls by their role or a click handler written in the markup, and these handles have neither. EaseWeb's audit sends a review lead for a colour square or a hue strip drawn with CSS gradients that has a handle but nothing in it that takes focus, no slider and no field, because only a person can try whether the colour can be set some other way on the page. Asked to fix the picker, a code assistant may add role="slider" and tabindex="0" to the square's handle and stop there: a slider has one value, the square has two, and no field appears for the code.
Try it
Drag the handles to change the brand colour. Then click the square somewhere else, and put the mouse aside and try Tab.
The panel shows what a screen reader announces. Can you set the colour without dragging, or type #2a9d8f?
Broken Can you fix this?
Screen reader says:
(Tab through the settings)
The fix
Give the picker a field to type the colour, and make its square and strip controls that take focus, read their values and move with keys and single clicks.
- 1The colour can be typed as a code, in a field with a name.
- 2Every part that sets the colour takes focus, reads its name and value, and moves with keys.
- 3Every colour can be set with clicks, taps or typing, not only a drag.
<div class="brand-colour"> <span class="label">Brand colour</span> <div class="sv-area" style="background-color: hsl(220 100% 50%)"> <span class="handle" style="left: 75%; top: 15%"></span> </div> <div class="hue-strip"> <span class="handle" style="left: 61%"></span> </div> <div class="preview" aria-hidden="true" style="--brand: #366cd9">…</div> <span class="hex">#366cd9</span></div>A hex field beside the picker
<div class="brand-colour" role="group" aria-labelledby="brand-label"> <span class="label" id="brand-label">Brand colour</span> <div class="sv-area" style="background-color: hsl(220 100% 50%)" aria-hidden="true"> <span class="handle" style="left: 75%; top: 15%"></span> </div> <div class="hue-strip" aria-hidden="true"> <span class="handle" style="left: 61%"></span> </div> <div class="preview" aria-hidden="true" style="--brand: #366cd9">…</div> <label for="brand-hex">Hex</label> <input type="text" id="brand-hex" value="#366cd9" maxlength="7" spellcheck="false" autocomplete="off"></div>The handles can't take focus, so the keyboard never reaches them. They have no role, name or value, so assistive technology doesn't know the picker is there. A press listener on the handles is the only way in, so every colour needs a drag, and the code is written out where no one can type.
The picker stays as it was for people who like to drag, and a labelled text field takes the colour as a code, by typing, pasting or voice. It is native, so it is in the Tab order with a role, a name ("Hex", in the group "Brand colour") and a value, and the drag writes into it, so it always shows the colour the handles have set. aria-hidden takes the drag-only square and strip out of the accessibility tree, so a screen reader meets the field and not two handles with no role or name. It is the smallest change to an existing picker, and it gives everyone an exact value. But it is not enough on its own: a keyboard or voice user who wants the same blue a little lighter has to work out a new code, while a mouse user just moves the handle. It suits a setting where people arrive with a code, such as a brand guide, more than one where they choose by eye.
All three pass. The hex field is the smallest change and gives everyone an exact value, but people who can't drag still choose colours only by code. The browser's own colour input is the least code, but every browser draws a different picker, not all of them take a typed value, and the page can't put it inline or style its pop-up. The sliders with the hex field are the only one that lets keyboard and screen reader users choose by eye or by code, the same in every browser, while keeping the picker as it was drawn; use them whenever the picker is your own.
What a screen reader reads should mean something to the person hearing it. A hex code means little to most people, and "75%" for saturation not much more, so name the hue in its aria-valuetext, and consider writing the whole colour's name beside its code ("dark blue"), where everyone can read it. The preview is a picture of the booking page, not a control, so it is hidden from assistive technology and drawn apart from the form's own buttons. Chrome gives screen readers its own colour input's value as percentages of red, green and blue ("21% red 42% green 85% blue").
A few things decide how the picker behaves once it is in a page.
- One Tab stop or two: the two inputs in the square are two Tab stops, which is simple and uses the browser's own keys. A library may keep the square to one Tab stop, with the left and right arrows moving one hidden input and the up and down arrows the other; React Aria's colour area works this way.
- Focus and contrast: the hidden inputs draw no focus ring, so draw one on the handle, for example with
.sv-area:has(:focus-visible) .handle. A white ring with a dark edge keeps the handle visible on every colour of the square; see low-contrast form fields, icons and focus rings. - The hex field: accept the code with or without the
#, and leave a code that isn't valid as it was typed, with a message beside the field rather than a silent reset; see form errors that don't say how to fix them. - Touch:
touch-action: noneon the square and the strip stops a drag on them from scrolling the page, but a finger can't scroll the page from there either, so keep them small enough that there is always room around them. - A picker that opens from the field: the square and the strip may pop up under the hex field when it takes focus, as long as focus stays in the field, typing still works, Escape closes them and they don't cover the next field. Content that appears without moving focus is a change of content, not of context, but it must stay open until focus leaves or the person closes it, and close without moving focus; see dropdowns and fields that change the page on their own and tooltips that vanish on approach and can't be dismissed.
- Forced colors: a contrast theme replaces the background colour that paints the square's hue and the preview, and removes the gradients that shade the square and draw the strip, so set
forced-color-adjust: noneon the square, the strip and the preview, and give the handles a border in a system colour.
Colour picker libraries vary. Some put role="slider" on the square with no aria-valuenow, which axe reports; some take keys but no press on the square; some have no field at all. Check what each part that takes focus exposes, not what the library's documentation promises.
Fixing this with an AI coding assistant? Get this guide as Markdown, or get every guide in your coding agent.
Design ideas
A colour can be typed, or picked from a palette, sliders or a wheel, all without a drag.
Five ways to draw the brand colour setting. Try each with clicks only, then Tab to it and use the arrow keys or type: four can be set without a drag and tell a screen reader what they are set to, and one gives a screen reader nothing but “button”.
In the design file
- Draw the colour’s code as a field people can type into, not as a line of text.
- Draw the field open and closed, and open the picker where it doesn’t cover the next field.
- Note that a click on the square, the strip or the wheel moves the handle there, as well as a drag.
- Give every colour in a palette a name people can read, such as Ocean or Coral, and show it on screen.
- Draw each handle as a white ring with a dark edge, and with its focus ring.
Passes
- A hex field that opens a picker Closed, a compact field with the colour in a small square at its start. Clicked or reached with Tab, it opens a small square and hue strip under it without taking the cursor out of the field: typing still works, a click in the square or the strip sets the colour without a drag, and Escape closes it. Keyboard users set the colour by its code.
- Swatch chips with their names Each colour is a pill with a dot and its name, the edge #6b7280 at 4.83:1; the chosen one takes a 2px #1a1a1a edge and a tick. People who can’t tell Forest from Slate read the name, a screen reader hears it, and the arrow keys move between the colours.
Brand colour
Three sliders that each draw their range Hue, saturation and brightness each get a track painted with the colours it runs through, and the value written at its end, “220°”, “75%”. A tap anywhere on a track sets it there, and the arrow keys step it, so no colour needs a drag.- Brand colourA colour wheel that takes a click A ring of hues with the chosen colour in the middle and its name under it. A click or tap anywhere on the ring moves the handle there, the way WCAG’s own example of a colour wheel works, and the arrow keys turn it round.
Fails
- Brand colourSwatch dots with no namesWCAG 4.1.2 Five neat dots, the chosen one with a tick. Tab reaches each, but a screen reader says only “button” five times, with nothing to tell Ocean from Coral or which one is chosen, and voice control has no name to call them by.
Verify the fix
5 checks.
Test with: Keyboard, Screen reader, Mouse, Touch
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the picker or its library changes.
Limits
This is a starting pattern, not a guarantee for every application. Screen readers differ in how they read range inputs: some read the value before the name, and on iOS they move by swiping up and down rather than with keys. The browser's own colour pickers change between versions, so check the ones your users have. A single slider for a price or a volume is covered in range sliders that only move by dragging, and gestures in general in pinch, drag and tilt gestures with no button. Whether white text stays readable on the colour someone picks is a separate check: see low-contrast text on brand colours, photos and hover states. Test the complete setting with your target assistive technology.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
References
- WCAG Understanding: dragging-movements (opens in a new tab)
- WCAG Technique F108 (opens in a new tab)
- WCAG Understanding: keyboard (opens in a new tab)
- WCAG Understanding: name-role-value (opens in a new tab)
- developer.mozilla.org: color (opens in a new tab)
- developer.mozilla.org: range (opens in a new tab)
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.