DEV Community

Ivan V.
Ivan V.

Posted on • Updated on

Using Next.js Link Component with Material UI Buttons and Menu Items

Update

  1. This blog post refers to Material-UI V4 but it should work with the V5 also.
  2. I've created a template repository for using Next.js with Material UI which you can use as a starting point.

demo: https://material-pwa.vercel.app/

repository: https://github.com/ivandotv/nextjs-material-pwa

Link component is a magic component of next.js framework, that does the routing both client-side and server-side (properly rendering links for SEO purposes).

Material UI is a most popular framework for implementing Google's material design system.
Since both frameworks expect a certain HTML structure to be present in order to render their components, using them together is not straightforward as it seems, luckily it's not that hard at all.

In this article, I'm going to show you how to properly render material UI buttons and menu items as nextjs links.

Rendering a material UI button is very easy, just wrap the button component with the nextjs link component and make sure you use passHref property on the link component.

<Link href="/about" passHref>
  <Button variant="contained" color="secondary">About</Button>
</Link>
Enter fullscreen mode Exit fullscreen mode

passHref must be used every time you use a custom component inside the Link component. Without it when you test your code client side it will appear that everything is working because the Link component will properly route the links however the generated a tag will not have a href property, so website crawlers will see no links, which will negatively impact your SEO.
The reason it appears that it works is that the link component has a value for href and it just listens to click events on its child components and then does the routing.

You can confirm this by disabling javascript in the browser and trying to navigate nextjs app, you will see that the links won't work.

Using ListItem Component

ListItem component is used inside all kinds of material UI menus, and it is a little bit trickier to set up because the generated HTML structure of the component is more complex than a simple button component.

Outhere on the internet you will find a lot of solutions that are using higher-order components and passing props all over the place however, the solution is very simple and it is offered by the API of the ListItem component itself.
What we need to do is to change the underlying element of the ListItem component to be an a tag. We can do this by using the component property of the ListItem.

<Link href="/about" passHref>
 <ListItem button component="a" onClick={onClick}>
  <ListItemText>About</ListItemText>
 </ListItem>
</Link>
Enter fullscreen mode Exit fullscreen mode

And that's it, links will work on the client-side, and they will be properly rendered on the server-side.

Top comments (10)

Collapse
 
codingjlu profile image
codingjlu

Okay... thanks for the article. Just want to point out though, that putting a button inside an <a> tag is invalid syntax. See stackoverflow.com/questions/639382....

Collapse
 
ivandotv profile image
Ivan V.

You can change the material ui button component to be represented with a different html element, so button could be represented with a div element.

Collapse
 
codingjlu profile image
codingjlu

Sure. I found this working for me and wanted to share it with anyone who'd think it's useful. In link.js:

import NextLink from "next/link";
import MuiLink from "@mui/material/Link";
import MuiButton from "@mui/material/Button";

export default function Link({ type, href, children, ...props }) {
  if (type === "link" || !type) {
    return (
      <NextLink href={href} passHref>
        <MuiLink {...props}>{children}</MuiLink>
      </NextLink>
    );
  } else if (type === "button") {
    return (
      <NextLink href={href} passHref>
        <MuiButton {...props}>{children}</MuiButton>
      </NextLink>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Then you can just use it as a utility components just like you would with Next and MUI's buttons:

import Link from "../path/to/link";
// Later...
<Link type="button" href="/somewhere">Yay!</Link>
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
cristianeto profile image
Cristian Guamán

super!!!

Thread Thread
 
petroswursta profile image
petros-wursta

I tried this but was not able to get it to work.

I added a links.js file and added your code.

then this
import Link from "../path/to/link";
// Later...
Yay!

but it doesn't work, I get the following error.

Any help please?!

Image description

Thread Thread
 
codingjlu profile image
codingjlu

Could you show a bit more code? Did you adjust the code to actually fit your project? Did you paste the correct code into your link component?

Thread Thread
 
petroswursta profile image
petros-wursta

Thank you! Looks like I got it to work. I needed to install the mui library.

I just need to add styling b/c it just shows up as texts instead of a button.

Thread Thread
 
codingjlu profile image
codingjlu

Great, glad it worked out!

Collapse
 
12dimov profile image
Vania Dimova

You are life saver, glad to see it in one page. This is how they should write docs! Thank you!

Collapse
 
fabarea profile image
Fabien Udriot

Very useful piece of information. Thanks.