Skip to content
Advertisement

Upgrade to material ui icons v5 broke react-select

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 muis 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.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement