Capabilities · API
EyeDropper API
Published
The EyeDropper API gives a page the browser’s own eyedropper tool: new EyeDropper().open() suppresses input to the page, lets the user pick one pixel anywhere on screen, including outside the browser window, and resolves with that pixel’s colour as a #rrggbb string. It exists so custom colour pickers do not have to screenshot the page to sample a colour.
Chrome 95 and Edge 95 ship it on desktop only; BCD records version_added: false for Chrome on Android and Android WebView. Firefox and Safari have no implementation (BCD api.EyeDropper). Chrome 96 moved the interface behind [SecureContext], so on http:// origins other than localhost window.EyeDropper is undefined.
Syntax
Section titled “Syntax”const eyeDropper = new EyeDropper();
eyeDropper.open()eyeDropper.open(options)The constructor takes no arguments and does nothing visible. open() returns a Promise<ColorSelectionResult>; the result’s only member is sRGBHex, a DOMString holding a valid simple colour such as "#3366ff". While the promise is pending the page is in “eyedropper mode” and receives no UI events. open() must be called with transient user activation, so it belongs inside a click or keydown handler.
Parameters
Section titled “Parameters”open() takes one optional options argument, a ColorSelectionOptions dictionary with a single member.
| Member | Type | Required | Description |
|---|---|---|---|
signal |
AbortSignal |
No | Aborting the signal exits eyedropper mode, dismisses the browser UI, and rejects the pending promise with the signal’s abort reason (an AbortError DOMException unless abort() was given another reason). |
The resolved ColorSelectionResult dictionary has one member, sRGBHex, a six-digit #rrggbb string. The specification exposes no alpha channel, so a translucent pixel is reported as the colour composited on screen.
Exceptions
Section titled “Exceptions”open() rejects its promise with one of the following. The first two are checked synchronously before any UI appears.
| Exception | Condition |
|---|---|
NotAllowedError |
The window has no transient user activation. |
InvalidStateError |
Another eyedropper is already open in this window. |
AbortError |
The user cancelled the selection (Escape in Chrome) before picking a pixel. |
OperationError |
The browser could not present its UI or could not read screen content; Chrome also uses it when the feature is disabled by policy. |
| The signal’s abort reason | options.signal was already aborted when open() was called, or was aborted while the promise was pending. |
Examples
Section titled “Examples”Both examples test "EyeDropper" in window before showing any pick button and keep an <input type="color"> in the page as the path for Firefox, Safari, and every mobile browser.
Picking a colour with a native colour input as the fallback
Section titled “Picking a colour with a native colour input as the fallback”When the constructor is missing, hide the pick button and leave the colour input visible; the input gives every browser a working colour picker, just not one that can sample pixels outside the page.
const pickButton = document.querySelector("#pick");const colorInput = document.querySelector("#color");
if (!("EyeDropper" in window)) { pickButton.hidden = true; colorInput.hidden = false;} else { pickButton.addEventListener("click", async () => { const eyeDropper = new EyeDropper(); try { const { sRGBHex } = await eyeDropper.open(); colorInput.value = sRGBHex; } catch (err) { if (err.name !== "AbortError") console.error(`${err.name}: ${err.message}`); } });}AbortError is the normal outcome when the user presses Escape, so the handler ignores it and surfaces only the other names.
Cancelling a pick from a timeout or a second button
Section titled “Cancelling a pick from a timeout or a second button”Pass an AbortSignal when a pick should not stay open indefinitely. AbortSignal.timeout() rejects with a TimeoutError reason, which the catch branch distinguishes from the user’s own cancel.
async function pickWithTimeout(ms) { if (!("EyeDropper" in window)) return null;
const eyeDropper = new EyeDropper(); try { const { sRGBHex } = await eyeDropper.open({ signal: AbortSignal.timeout(ms) }); return sRGBHex; } catch (err) { if (err.name === "TimeoutError") console.info("Eyedropper closed after timeout"); return null; }}
document.querySelector("#pick").addEventListener("click", async () => { const hex = await pickWithTimeout(10_000); if (hex) document.documentElement.style.setProperty("--accent", hex);});A null return covers unsupported browsers, timeouts, and user cancellation alike, so the caller needs one branch rather than three.
See also
Section titled “See also”- Async Clipboard API, for copying the sampled value out of the page
- Local Font Access API, the other desktop-only Chromium creative-tools API
- Screen Capture API, the heavier way to read pixels outside the page
- EyeDropper API (wicg.github.io)
- Picking colors of any pixel on the screen with the EyeDropper API (developer.chrome.com)
Specifications
| Specification | Status |
|---|---|
| EyeDropper API | WICG draft |