[docs] Using custom SvgIcon with SVGR does not work as described in the docs, with next.js App Router
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 99.1k
- Forks
- 32.5k
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 106
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 (https://github.com/gregberge/svgr/issues/897#issuecomment-1762463668), 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...
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the related Material UI icons page and the material-ui-nextjs-ts example, then reproduce the custom SVG setup in layout.tsx. Compare the documented component prop usage with the App Router behavior and the next.config.js webpack configuration. Done means the documentation provides a working App Router example and the example can be followed without the reported errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, next.js, react, typescript
- Domain
- documentation, frontend
- Issue type
- Documentation
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100