Description
We're working on a new feature/release that I thought was worth documenting the plan and rationale here for ahead of the PRs and releases coming for it. If you've got any feedback, please share below.
Goal 1: Tailwind Support
Tailwind (and other utility class frameworks) have gained a lot of momentum recently, and with increasing diversity of new front-end frameworks and build systems, it's less easy than it used to be to assume that CSS-in-JS / Emotion will "Just Work" for everyone. In particular, if you're building your own component library / design system with something like Tailwind and using React Select it's a fair bit of work to map design tokens and theme properly from CSS classes to React Select's theme context.
Wouldn't it be better if you could just style React Select with your own class names? that's the plan 😁
The new classNames
API
Step one is adding a new classNames
API. A small nod to a popular library, this will sit alongside the current styles
prop, and let you provide (as the name suggests) class names instead of css property values for each Component in React Select, based on the same state argument provided to the styles
functions.
So if you wanted a red border around your Select component on focus, where currently you could do this:
<Select styles={{
control: (styles, { isFocused }) => ({ ...styles, borderColor: isFocused ? 'grey' : 'red' })
}} />
Now you can apply class names to get the same effect:
<Select classNames={{
control: ({ isFocused }) => isFocused ? 'border-red-600' : 'border-grey-300'
}} />
ℹ️ Note: you won't have a good time using tailwind's native support for pseudo-states, because the browser doesn't think the Control component is focused when the input or menu are "focused" (internally we call this "pseudo-focus") so classes like focus:border-grey-300
won't work. This is why we're sticking with the (state) => string
signature for the new prop
Goal 2: The new unstyled
prop
Not necessarily in the same release (depends on how the implementation plays out) but we're also planning to introduce an unstyled
prop which will remove all the presentation styles from React Select (leaving some important functional styles, like those for menu positioning and input width in multi select)
This will make it easier to completely specify your own styles or classNames to control the look of React Select, without having to specifically override the default theme we apply.
ℹ️ Note: removing the dependency on emotion
for styles isn't specifically part of this same goal, although the two are related; the new unstyled
prop is specifically only to make theming-from-scratch easier. We'll (probably) still be using emotion under the hood for applying functional styles.
Goal 3: Decouple from Emotion
This is a longer-term thing that we're going to experiment with, but will have to see how things play out – actually shipping it may require a rework of how the component is bundled, and how the entry points work, which would mean a new major. We'll see.
But theoretically there are a few wins here to be had:
- Provide CSS as classNames to the base component, even when using Emotion to generate them
- Export the functions used to style React Select with the default theme, so they can be extended or applied in with the
classNames
prop in user land, but using any css-in-js library - Move functional CSS (like menu positioning) to inline styles, and then provide an
unstyled
export with no dependency on css-in-js at all so consumers providing their own classNames don't have to bundle a copy of Emotion that they don't need
Long term we expect to continue using Emotion as the built-in "just works out of the box" solution for styling React Select, but it would be great to offer more flexibility and reduced bundle size for people who want to include their own solution. So, this is our current plan and roadmap for that.
Watch this issue for PRs that come in as we work through the backlog, and shout out if you have any other ideas for how we might go about improving this part of React Select!