I have been upgrading from @material-ui/icons
4.11.2 to @mui/material
and @mui/icons-material
at 5.2.3
I realize that material UI is not directly used in react-select however as far as I can see there is some interaction.
The upgrade from Material UI Icons v4 to v5 seemed to be going fine. But then, I noticed all the react-select dropdowns explode the application (instant blank screen) with this error in the console:
TypeError: theme.transitions is undefined ./node_modules/@mui/material/SvgIcon/SvgIcon.js/SvgIconRoot< node_modules/@mui/material/SvgIcon/SvgIcon.js:49
46 | display: 'inline-block', 47 | fill: 'currentColor', 48 | flexShrink: 0, 49 | transition: theme.transitions.create('fill', { | ^ 50 | duration: theme.transitions.duration.shorter 51 | }), 52 | fontSize: {
I’ve been pouring over the Material UI v4 -> v5 migration guide, have upgraded our react
and react-dom
libraries to 17.0.2 and react-select
library to 5.2.1, but this issue persists.
Here’s my function component that wraps all the dropdown selectors in question.
import React, {useState} from 'react'; import Select from 'react-select'; import {useSelector} from "react-redux"; import "./EntityChildDropdownSelector.scss" import {selectStyles, selectTheme} from "./SelectorStyles"; import SearchIcon from '@mui/icons-material/Search'; import PropTypes from "prop-types"; /** EntityChildDropdownSelector for editing one attribute of an entity @return {*} @typedef EntitiesSelector{Selector} is a Redux selector that can be used to fetch the entities for this selector @typedef Entity{{ id:String }} is an entity having an id @typedef TextFormattingFunction{function} given an entity, returns it formatted as text @typedef ClassName{string} of attribute to edit @typedef ActivateFunction{function} to callback when a selection is made */ const EntityChildDropdownSelector = function (props) { const [isOpen, setIsOpen] = useState(false); // option object has id and text, must be translated back and forth value <> riek field const entities = useSelector(state => props.entitiesSelector(state)), options = entities .map((o) => ({value: o.id, label: props.format(o)})), active = !!props.active ? options.find((o) => (o.value === props.active.id)) : null; const toggleOpen = () => { setIsOpen(!isOpen); }, onSelectChange = option => { toggleOpen(); props.onActivate(option.value); }; options?.length && !active && props.onActivate(options[0].value); return ( <div> <Select autoFocus classNamePrefix="selector" options={options} value={active} backspaceRemovesValue={false} components={{DropdownIndicator: SearchIcon, IndicatorSeparator: null}} controlShouldRenderValue={false} hideSelectedOptions={false} isClearable={false} menuIsOpen onChange={onSelectChange} placeholder="Search..." styles={selectStyles(200)} theme={selectTheme} tabSelectsValue={false}/> </div> ); } EntityChildDropdownSelector.propTypes = { entitiesSelector: PropTypes.func.isRequired, format: PropTypes.func, className: PropTypes.string, active: PropTypes.object, onActivate: PropTypes.func.isRequired, }; export default EntityChildDropdownSelector;
Also posted this issue to the react-select library.
Advertisement
Answer
(This is a copy of my answer given in the linked GitHub issue):
react-select
uses its own theme
prop for simple style customization which clashes with mui
s theme
prop.
You should wrap SearchIcon
with a function and an instance of the original DropdownIndicator
to keep the props from spreading onto the icon component, but to also retain normal functionality:
import Select, { components } from "react-select"; const DropdownIndicator = (props) => (<components.DropdownIndicator {...props}> <SearchIcon /> </components.DropdownIndicator>); <Select components={{ DropdownIndicator }} />
PS: You could also just use a <div>
element as a wrapper (with props.innerProps
as props), but the default DropdownIndicator
component (from components
) applies basic container styling and classnames.