MUI Icons used in shared React component library won't render: Error: Element type is invalid: expected a string or a class/function but got: object
Asked Answered
P

3

11

I've created a monorepo with a shared component library, but when I import components from that library that contain a MUI icon from @mui/icons-material I get the following error:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

This is what I get when I console.log() an imported Icon

import AddIcon from '@mui/icons-material/Save';
console.log(AddIcon)

{
  default: {
    '$$typeof': Symbol(react.memo),
    type: { '$$typeof': Symbol(react.forward_ref), render: [Function] },
    compare: null
  }
}

Everything else in the shared components is working fine, including the regular MUI components, and the icons work normally if I'm just adding them directly to my project so I can't figure out why they break in the shared components.

I have "@mui/icons-material": "^5.6.1" in the peerDependencies of my shared library and "@mui/icons-material": "^5.6.1" as a dependency in the project that I'm importing the shared components to.

Perdu answered 26/4, 2022 at 4:21 Comment(3)
It's an issue anytime there is an Icon is inside of the shared component I'm importing. If the Shared component were simply a button with an icon it would throw the same error I described: <Button><AddIcon /></Button> would not work but just <Button></Button> wouldPerdu
Having the exact same problem. I'm using Vite to test, tsc to build my packages. Seems somehow the default import gets messed up because the content of default in your console.log(AddIcon) is what should be the actual AddIcon...Nga
This is apparently an issue within MUI not having proper ESM compatibility for its icons: github.com/mui/material-ui/issues/35233Aaberg
N
5

Ran into the same issue using MUI with the turbo repo design starter (tsup). I don't like this hack, but it does appear to work.

import SaveBase from '@mui/icons-material/Save';
import SvgIcon from '@mui/material/SvgIcon/SvgIcon';

const normalizeIcon = (Icon: typeof SvgIcon) => {
  return ((Icon as any).default ? (Icon as any).default : Icon) as typeof SvgIcon;
};

const SaveIcon = normalizeIcon(SaveBase);

<SaveIcon />
Neighborhood answered 28/11, 2022 at 6:18 Comment(0)
C
3

Changing the import also works for me.

from

// import ([\w]+) from '@mui/icons-material/([\w]+)'
import MenuIcon from '@mui/icons-material/Menu';

to

// import { $2 as $1 } from '@mui/icons-material'
import { Menu as MenuIcon } from '@mui/icons-material';
Chaing answered 27/7, 2023 at 16:8 Comment(0)
N
0

I built my packages with both commonjs and es modules. I have the commonjs in the root of the package and es modules in an esm/ subdirectory. In my esm/ subdirectory I have a package.json with just {"type": "module"}. I'm not using exports in the root package.json, but just main and module where module points to ./esm/index.js. The output in esm/ actually is the result of tsc --target es6 --module esnext --outDir ./build/esm.

With package.json in esm/ subdirectory I get the exact error you pointed out and the icon import will be an object with default that points to the expected imported data. However, if I delete the package.json in esm/ all is fine again. It also seems to greatly reduce startup time, so I'm guessing something is broken in my package setup.

I'm not sure if this also applies to you, but the symptons are definitely the same.

Nga answered 2/9, 2022 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.