EyeDropper API: Sample Any Pixel on Screen in 2026
How the EyeDropper API lets a web app sample any pixel on the screen, the exact JavaScript to call it, and the fallback you still need in 2026.
EyeDropper API: Sample Any Pixel on Screen From the Browser
The EyeDropper API gives a web app something that was impossible for years: a native tool that samples the color of any pixel on the user's screen, including pixels rendered outside the browser tab. You open it from a click, the cursor turns into a magnifier, the user clicks a pixel, and you get back a hex string. This post covers the exact JavaScript, the browser-support reality in 2026, and the fallback you still have to ship.
TL;DR
new EyeDropper().open()returns a promise resolving to{ sRGBHex }.- Chromium desktop only — Chrome 95+ and Edge 95+; no Firefox, Safari, or mobile.
open()requires a user gesture and a secure (HTTPS) context.- Always feature-detect with
'EyeDropper' in windowand ship a fallback. - The API returns hex only; convert to RGB, HSL, or OKLCH yourself.
What is the EyeDropper API?
Creative desktop apps have had eyedroppers forever. Photoshop samples a color off the canvas; PowerPoint pulls a fill color from anywhere on screen; even Chrome DevTools has one in the CSS color editor. On the web, none of that was possible without hacks. The closest native option was the <input type="color"> picker, which on Chromium desktop hides an eyedropper inside its dropdown — but you can't style it, script it cleanly, or reach it in other browsers.
The gap it fills
The EyeDropper API closes that gap by exposing the browser's own screen-sampling tool directly. According to the MDN EyeDropper API reference, the tool can sample colors "including outside of the browser window" — that's the part <input type="color"> never gave you programmatically.
What it returns
Per the WICG specification, open() resolves to a ColorSelectionResult dictionary with exactly one member: sRGBHex, a valid simple color string in #RRGGBB form. No alpha, no named channels, no color space choice. One hex string per pick.
Who shipped it
The API was specified and implemented by Ionel Popescu of the Microsoft Edge team, which is why Edge and Chrome shipped it in the same release. It lives in the WICG (Web Incubator Community Group), not yet in a W3C Recommendation, so it's still officially experimental.
How to use the EyeDropper API in JavaScript
The surface area is tiny: one constructor, one method. The important details are the promise flow and the two things the browser enforces — a user gesture and a secure context.
Feature detection first
Never call the constructor blind. It doesn't exist in Firefox or Safari, so touching it throws. Guard with a simple in check:
if ('EyeDropper' in window) {
// API is available
} else {
// show your fallback picker
}
Opening the eyedropper
Create an EyeDropper instance and call open() inside a click handler. It returns a promise that resolves when the user clicks a pixel and rejects when they hit Escape:
const btn = document.querySelector('#pick');
btn.addEventListener('click', async () => {
const dropper = new EyeDropper();
try {
const { sRGBHex } = await dropper.open();
console.log('picked', sRGBHex); // "#4f46e5"
} catch (err) {
// user pressed Escape — not an error
}
});
Two rules the browser enforces here. First, open() needs transient activation — call it outside a real user gesture and the promise rejects with NotAllowedError. Second, the interface is SecureContext, so it only exists on HTTPS (or localhost). On plain HTTP, window.EyeDropper is undefined.
Cancelling with AbortController
If your app state changes mid-pick — a modal opens, the user navigates away — you can cancel the eyedropper yourself with an AbortSignal:
const ctrl = new AbortController();
dropper
.open({ signal: ctrl.signal })
.then(r => console.log(r.sRGBHex))
.catch(() => {}); // aborted or escaped
// later, to force-close it:
ctrl.abort();
One more spec detail worth knowing: only one eyedropper can be open at a time. Calling open() while another is active rejects with InvalidStateError. Track your own open state if you wire the tool to multiple buttons.
Why does the EyeDropper API only work in Chrome and Edge?
This is the question that decides your architecture. The API is Chromium-only, and there's no sign of that changing in 2026.
The support matrix
Here's where things stand on desktop, per the Chrome for Developers guide and the caniuse support table:
| Browser | Support |
|---|---|
| Chrome | 95+ (desktop) |
| Edge | 95+ (desktop) |
| Firefox | Not supported |
| Safari | Not supported |
Mobile is a flat no across the board — neither Chrome for Android nor Safari on iOS exposes it, because there's no on-screen cursor metaphor to sample with on touch.
Why Firefox and Safari haven't shipped
Both projects have open position requests but no implementation. MDN flags the feature as not Baseline precisely because it's missing from widely-used engines. Treat it as a progressive enhancement, never a hard dependency.
What this means in practice
- Roughly two-thirds of desktop users get the native picker.
- Every Firefox, Safari, and mobile user needs a fallback.
- You cannot detect support by browser name — feature-detect at runtime.
How to build a fallback color picker when EyeDropper is missing
Because coverage is partial, a shippable feature branches on detection. The good news: the fallback is a one-line native element that every browser has supported for a decade.
Branch on feature detection
Use the native <input type="color"> when the API is absent. It won't sample outside the page, but it gives users a working picker everywhere:
async function pickColor() {
if ('EyeDropper' in window) {
const { sRGBHex } = await new EyeDropper().open();
return sRGBHex;
}
// fallback: native color input
return new Promise(resolve => {
const input = document.createElement('input');
input.type = 'color';
input.addEventListener('input', () =>
resolve(input.value)
);
input.click();
});
}
Convert the hex you get back
Both paths hand you a hex string, but design systems usually want RGB, HSL, or OKLCH. The EyeDropper API won't convert for you. Drop the value into a color converter to get every format at once, or pipe several samples into a color palette generator to build a scheme from what you picked off the screen. If you're sampling two ends of a scale, a gradient generator turns two picked stops into a ready CSS gradient.
Store and reuse samples
A common pattern is a "recent colors" strip. Keep an array of the hex strings you collected, dedupe, and render swatches. Since the API returns plain #RRGGBB, they slot straight into CSS custom properties with no parsing:
const recent = [];
function remember(hex) {
if (!recent.includes(hex)) recent.unshift(hex);
document.documentElement.style
.setProperty('--last-pick', hex);
}
Security and privacy: can a website read my screen?
An API that reads arbitrary screen pixels sounds alarming. The spec is built around making silent screen-scraping impossible, and it's worth understanding the four guardrails.
The four guardrails
The WICG spec's security section and MDN both spell these out:
- User gesture required.
open()only runs from a real interaction like a click. - No background reads. The promise resolves only after the user clicks a pixel — moving the mouse leaks nothing.
- Obvious mode. The normal cursor disappears and a magnifier appears, with a deliberate delay so the user notices before any pick is possible.
- Always cancellable. Escape exits the mode, and the page can't suppress that.
Why the delay matters
That enforced delay between opening the tool and allowing a selection isn't a UX afterthought — it's a defense. It guarantees the user sees the eyedropper UI before any pixel can be captured, so a page can't flash the tool open and closed to grab a color the user never meant to share.
It's still local-only
The color never leaves the device unless your app sends it somewhere. Sampling happens entirely in the browser, which is the same privacy posture as every tool on iKit — the pixels stay on the user's machine. That's a genuine selling point when your users are pulling brand colors off confidential mockups.
References
- EyeDropper API — MDN Web Docs — concept, secure-context requirement, and the security-measures list.
- Picking colors of any pixel on the screen with the EyeDropper API — Chrome for Developers — feature detection, AbortController usage, and version support.
- EyeDropper API — WICG specification draft —
ColorSelectionResult/ColorSelectionOptionsdictionaries and theopen()algorithm. - EyeDropper API: open — Can I use — current Chrome/Edge/Firefox/Safari support figures.
Related on iKit
- Turn a picked hex value into RGB, HSL, and OKLCH in one paste — the math behind converting the
#RRGGBBstring the eyedropper hands you. - Go the other way: build a hex string from RGB channels — useful when you sample in RGB tooling but need hex for CSS.
- Use OKLCH for the colors you sampled — a practical guide to expressing picked colors in a perceptual color space.
- Build a perceptually uniform ramp from a sampled base color — turn one eyedropper pick into a full tonal scale.
- Why design systems are moving from HSL to OKLCH — context for which space to store your sampled colors in.
- Check the contrast of a color you just picked — verify a sampled foreground/background pair passes WCAG AA or AAA.
Related posts
CSS Color Module Level 4: Every New Function (2026)
CSS Color Module Level 4 added oklch, oklab, lab, lch, hwb and color(). Here is what each function does, the exact value ranges, and 2026 browser support.
WCAG Contrast Ratios: How AA and AAA Are Calculated (2026)
A developer's guide to the WCAG contrast ratio formula, the 4.5:1 AA and 7:1 AAA thresholds, large-text exceptions, and how to check color contrast in code.
OKLCH in CSS: A Practical Guide for Developers (2026)
OKLCH in CSS gives you perceptually uniform color, wider P3 gamut, and predictable lightness. Here is the syntax, the math, and the fallbacks for 2026.