Selectlist is an upcoming element that replaces the native select element with a fully stylable and customizable one, while still keeping all the native interactions and accessibility features. It's a sorely needed improvement and will let you do away with all your custom select implementations.
Selectlist is an experimental feature. It's still being worked on and you can't use it in browsers yet, unless you use Polypane (...or a Chromium based browser where you have experimental features turned on.)
This isn't a full exploration of what selectlist
is and can do, but a quick explainer of how to get selectlist
to play nicely with React. We ran into issues while replacing some of the select
elements in the Polypane UI, which is built with React, and we hope this prevents you from running into the same issues. For a nice introduction, check out Hidde's article Two levels of customising <selectlist>
and for a full explainer, head over to OpenUI which is where the element is being developed.
Select in React
When you want to do something when the value in your regular select changes in th regular React way, you use the onChange
prop:
<select onChange={(e) => doSomething(e)}>
<option value="hex">Hex</option>
<option value="rgb">Rgb</option>
<option value="hsl">HSL</option>
</select>
And every time a user picks a new option, the onChange is fired and you can handle whatever you need to do with the event.
Selectlist in React
To "migrate" from select
to selectlist
, you'd expect to be able to just swap them out:
<selectlist onChange={(e) => doSomething(e)}>
<option value="hex">Hex</option>
<option value="rgb">Rgb</option>
<option value="hsl">HSL</option>
</selectlist>
Unfortunately, that's not the case. When you do that you'll notice that while the selectlist
value updates, onChange
doesn't fire. That's because the onChange prop is a React concept, not a different notation for the DOM native change
event.
React has specific code that calls the onChange
function whenever the change
event fires on select
elements, but it doesn't know about selectlist
yet so the onChange
on selectlist
doesn't get called.
To make it work, we need to add the listeners ourselves using useEffect and useRef:
import { useEffect, useRef } from 'react';
const OurComponent = () => {
const selectlist = useRef();
useEffect(() => {
const currentSelectlist = selectlist.current;
currentSelectlist.addEventListener('change', doSomething);
return () => {
currentSelectlist.removeEventListener('change', doSomething);
};
}, []);
function doSomething(e) {
// do something with the event
}
return (
<selectlist ref={selectlist}>
<option value="hex">Hex</option>
<option value="rgb">Rgb</option>
<option value="hsl">HSL</option>
</selectlist>
);
};
We use a ref to get the actual DOM element of the selectlist
, and then use useEffect
to add (and remove) event listeners to it manually. The listener doesn't need to change when we update the element, so we add an empty array as the dependency array of the useEffect.
To prevent event listeners from hanging around and taking up memory after we've removed the element from the DOM, we also add a return function to the useEffect
to remove the event listener when the component unmounts.
Selectlist as a separate React component
You probably don't want to add that useEffect to each component you use a Selectlist in, so instead you can extract it into its own component:
import { useEffect, useRef } from 'react';
const Selectlist = ({ onChange, children, value }) => {
const ref = useRef();
useEffect(() => {
const selectlist = ref.current;
selectlist.addEventListener('change', onChange);
return () => selectlist.removeEventListener('change', onChange);
}, [onChange]);
return (
<selectlist ref={ref} value={value}>
{children}
</selectlist>
);
};
// and then use it like this:
const OurComponent = () => {
// do your domain specific stuff
return (
<div>
{/* your other component parts */}
<Selectlist onChange={doSomething} value={value}>
<option value="hex">Hex</option>
<option value="rgb">Rgb</option>
<option value="hsl">HSL</option>
</Selectlist>
</div>
);
};
And that's how you can use selectlist
in React.
Keep in mind that selectlist
isn't something you can use in the wild and have work for your visitors, and that it's still in development so things might change.
We have the luxury of determining our own browser support and we're happily using it inside Polypane to improve how our Selects work without sacrificing on accessibility or existing user expectations. If you want to play around with selectlist
too, try Polypane for free.