With the new EyeDropper API in Chromium, websites can let visitors pick colors from anywhere on their screen, adding another feature to the web that used to require hacky solutions and is now just a few lines of code. The API is clean and modern and easy to use. In this article, we'll discuss how to set it up, handle edge cases, and additional features we hope will land in future updates.
We've been following the EyeDropper API since it was first proposed and have been experimenting with it as different parts became available as well as providing input while the feature was being developed.
The API adds a new global, EyeDropper
(or window.EyeDropper
) that you can use to set up a new eyedropper object:
const eyeDropper = new EyeDropper();
This eyeDropper object has one function, eyeDropper.open()
. This starts the color picker and changes the user’s cursor into a color picker, complete with a magnified area and a highlighted pixel. This function returns a promise, so you can use it either with await
or as a promise.
One gotcha is that it only works when called from a user-initiated event. This is part of the security model, to prevent websites from potentially scraping pixels without the user knowing.
Because the API is only available in Chromium you will need to check for support before using it. The most straightforward way to do that is to only offer your color picking UI when window.EyeDropper
is not undefined:
if (window.EyeDropper) {
// Okay to use EyeDropper
} else {
// Hide the UI
}
await
based version// won't work
const result = await eyeDropper.open();
// works
document.queryselector('.colorbutton')
.addEventListener('click', async () => {
const result = await eyeDropper.open();
});
The eyeDropper.open()
call will resolve in two situations:
The user clicks anywhere on the screen.
The user pressed the <kbd>Esc</kbd> key.
In the last situation the eyeDropper will throw an exception, but in the first situation you will get a ColorSelectionResult
object, which has an sRGBHex
property containing the picked color in hexadecimal format. In your code, you can check if result.sRGBHex
is defined and then do with it what you want.
document.queryselector('.colorbutton')
.addEventListener('click', async () => {
const result = await eyeDropper.open();
if (result.sRGBHex) {
console.log(result.sRGBHex);
}
});
You don't have to handle the exception but if you wanted to provide the user feedback that they canceled the eyedropper, you need to add a try .. catch
to the code:
document.queryselector('.colorbutton')
.addEventListener('click', async () => {
try {
const result = await eyeDropper.open();
if (result.sRGBHex) {
console.log(result.sRGBHex);
}
} catch (e) {
console.log(e);
// "DOMException: The user canceled the selection."
}
});
You don't have to use the await
version. eyeDropper.open()
returns a promise, so adding a .then()
and .catch()
also works:
document.queryselector('.colorbutton')
.addEventListener('click', () => {
eyeDropper
.open()
.then((result) => {
console.log(result.sRGBHex);
})
.catch((e) => {
console.log(e);
// "DOMException: The user canceled the selection."
});
});
There are two gotchas with the API, at least as it's currently implemented in Chromium that we've found that you should be aware of.
At least in the current implementation, the color picker gets the pixels as shown on the screen when you call .open()
. This means that if you're playing video the color picker will show the pixels of the frame that was visible then, not the live video. This is dependent on the implementation and we hope a future update of Chromium will allow for live data.
As mentioned earlier you need a user-initiated event to open the eyedropper. This is to prevent sites from opening the eyedropper UI to start scraping your screen right on load. Instead, the user needs to perform an action for the API to work, like a click or keypress.
The EyeDropper API is still very young and minimal. During our implementation, we encountered a number of features that we would like to see added to the API in future updates.
A major component of many eye droppers, like those in design tools, is that they also show a preview swatch of the hovered color. You can use this to compare it to another swatch or quickly check a HEX code. The current API does not offer this over security concerns. We have filed an issue against the EyeDropper API on GitHub for this: #6 Live feedback is needed.
Currently, all colors are returned in the sRGB color model. This means the API won't accurately return colors outside the sRGB spectrum, for example, those on Apple's P3 screens. How to deal with this is an open issue. Work is also happening on a new Color API for the web. The EyeDropper API could use this Color API when it lands in future versions of browsers.
Because of the current security model, each time a user picks a color they need to re-initiate a user action which can be tedious. For example, if you want to create a palette of colors in one go, you want to start picking colors, click on all the colors you want to add, and then close out of the eyedropper. We similarly filed an issue for this on Github: #9 Do we expect multiselect to work? and this feature is currently being considered.
For this, it would be nice if we could designate a part of the page (like a button) as an area where the EyeDropper doesn't work, that instead functions as a "done" button. This way users can select multiple colors and then click that button when they're done.
For now, the API is only available in Chromium-based browsers from version 95 on and there has not been a signal from Safari and Firefox yet. If you want those browsers to support the EyeDropper API as well, add your support to the open issues: Issue #1728527 for Firefox and Issue #229755 for Safari.
The EyeDropper API is a nice addition to the browser that we hope to see land in more browsers. We make good use of it in Polypane and would like to see it be developed further.
First Published here