Description
Duplicates
- I have searched the existing issues
Related page
https://mui.com/material-ui/icons/#component-prop
Kind of issue
Broken demonstration
Issue description
Yesterday I started working with Material UI's Next.js App Router typescript example. First thing I tried doing was replacing the DashboardIcon with a custom svg logo.
I tried following the example code at https://mui.com/material-ui/icons/#component-prop, and immediately started getting issues:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of
MuiSvgIconRoot
.
Lots of debugging and issue hunting later, I put a more complicated webpack config into next.config.js
, as suggested in various Github issues, including (but not limited to) in the svgr and next.js repos:
module.exports = {
webpack: (config, options) => {
// Grab the existing rule that handles SVG imports
const fileLoaderRule = config.module.rules.find((rule) =>
rule.test?.test?.('.svg'),
)
config.module.rules.push(
// Reapply the existing rule, but only for svg imports ending in ?url
{
...fileLoaderRule,
test: /\.svg$/i,
resourceQuery: /\.svg\?url$/,
},
// Convert all other *.svg imports to React components
{
test: /\.svg$/i,
issuer: fileLoaderRule.issuer,
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /\.svg\?url$/] },
use: [{
loader: '@svgr/webpack',
options: {
icon: 24,
}
}]
},
)
// Modify the file loader rule to ignore *.svg, since we have it handled now.
fileLoaderRule.exclude = /\.svg$/i
return config
},
// [snip]
(My only addition here is to add the icon: 24
svgr/webpack
option, otherwise my icon took up the full page)
However, using the <SvgIcon component={MyIcon} />
syntax in layout.tsx
, I got another error:
Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
{$$typeof: ..., render: function}
^^^^^^^^
I managed to get around this, by restructuring my layout.tsx
like so:
<SvgIcon>
<MyIcon />
</SvgIcon>
I don't pretend to be a pro when it comes to next.js
, webpack
, and certainly not material-ui
, which I'm only just starting to try and use, so I'm not suggesting this is the best solution or anything. But currently, the code examples in the docs don't work with the Next.js App Router, and it has taken me a full day's worth of time to come up with a working solution.
One other nice suggestion, by @pascalpp (gregberge/svgr#897 (comment)), is to add a types.ts
file, which allows us to fallback to the default next.js webpack loader for svg files, by appending a string to the end of the URL:
declare module '*.svg?url' {
import { FC, SVGProps } from 'react'
const content: FC<SVGProps<SVGElement>>
export default content
}
However, this uses react's
SVGProps
, instead of material-ui
's SvgIconProps
or SvgIconOwnProps
. I tried changing SVGProps
for SvgIcon{Own,}Props
, but it didn't work and I've given up on this for now.
Any feedback on this would be appreciated.
Context 🔦
I was just trying to replace the homepage icon with a custom svg logo. Followed code examples in the docs, but it didn't work...