mui / mui/material-ui

[docs] Using custom SvgIcon with SVGR does not work as described in the docs, with next.js App Router

Open
#39,974 6 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

component: SvgIcon nextjs scope: icons support: docs-feedback
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.