Skip to content

EyeDropper API: sampling on-screen colors

Published

In one line: per Chrome for Developers, “the EyeDropper API enables authors to use a browser-supplied eyedropper in the construction of custom color pickers,” letting a page sample the color of any on-screen pixel — including pixels outside the browser window — without shipping its own color-sampling code.

Per Chrome for Developers, open() “can only be called in response to a user action (like a button click),” so the call belongs inside the click handler itself — pasting it at the top level of a script will not start the eyedropper:

const pickButton = document.createElement("button");
pickButton.textContent = "Pick color";
const colorInput = document.createElement("input");
colorInput.type = "color";
document.body.append(pickButton, colorInput);
pickButton.addEventListener("click", async () => {
const eyeDropper = new EyeDropper();
try {
const result = await eyeDropper.open();
colorInput.value = result.sRGBHex; // e.g. "#3366ff"
} catch (err) {
// Rejects if the user cancels the pick, e.g. by pressing Escape.
console.log("Eyedropper pick cancelled:", err);
}
});

The open() method, per Chrome for Developers, “returns a promise that resolves after the user selects a pixel on the screen,” and the resolved value gives “access to the pixel’s color in sRGBHex format (#RRGGBB).” The promise rejects when the user cancels instead of picking a pixel; the example handles that rejection with try/catch.

Chrome for Developers is direct about the activation requirement: “the API doesn’t actually let the eyedropper mode start without user intent. The open() method can only be called in response to a user action (like a button click).” Calling open() outside a click or similar user gesture handler will not start the eyedropper.

open() also accepts an AbortSignal so an in-progress pick can be cancelled programmatically, in addition to the user pressing Escape:

const controller = new AbortController();
eyeDropper.open({ signal: controller.signal }).catch(() => {
// Rejects if the user cancels (e.g. presses Escape) or the signal aborts.
});
// Elsewhere, e.g. on a "Cancel" button:
controller.abort();

"EyeDropper" in window is false in every browser that doesn’t implement the API (Firefox, Safari). The fallback branch below actually shows the <input type="color"> swatch instead of the pick button, rather than just noting that it should:

function initColorPicker(pickButton, colorInput) {
if (!("EyeDropper" in window)) {
// No native eyedropper here — hide the pick button and let users pick a color
// with the always-present <input type="color"> swatch instead.
pickButton.hidden = true;
colorInput.hidden = false;
return;
}
pickButton.hidden = false;
pickButton.addEventListener("click", async () => {
const eyeDropper = new EyeDropper();
try {
const { sRGBHex } = await eyeDropper.open();
colorInput.value = sRGBHex;
} catch (err) {
// Rejects if the user cancels the pick, e.g. by pressing Escape.
console.log("Eyedropper pick cancelled:", err);
}
});
}
const pickButton = document.createElement("button");
pickButton.textContent = "Pick color";
const colorInput = document.createElement("input");
colorInput.type = "color";
colorInput.hidden = true;
document.body.append(pickButton, colorInput);
initColorPicker(pickButton, colorInput);

Per MDN, the EyeDropper API “is not Baseline because it does not work in some of the most widely-used browsers.” Per Chrome for Developers, the API is supported “on Chromium-based browsers like Edge or Chrome as of version 95”; per caniuse’s tracking of the feature, support also extends to Opera. Chrome for Developers’ own walkthrough runs the demo “on Windows or Mac,” consistent with the API being desktop-only in Chromium’s implementation. Firefox and Safari do not implement the EyeDropper API.

  • Feature-detect "EyeDropper" in window before constructing one — support is limited to Chromium desktop browsers (Chrome/Edge 95+), per MDN and Chrome for Developers.
  • Only call open() from inside a user-gesture handler (e.g. a click listener) — per Chrome for Developers, it “can only be called in response to a user action.”
  • Handle the rejected promise from open() — it rejects if the user cancels the pick (for example by pressing Escape) instead of selecting a pixel.
  • Pass an AbortSignal if your UI needs to cancel an open eyedropper programmatically, such as when the picker’s host dialog is dismissed.
  • Provide a fallback color input (e.g. <input type="color">) for browsers without EyeDropper, since Firefox and Safari do not implement it.