Moshe
Moshe

Reputation: 7007

Using the Material UI Link component with the Next.JS Link Component

I am using Material-UI with Next.js. I would like to use the Material-UI Link component so that I can access to the variant and other Material UI related API props. At the same time, I need to use the Next.js Link component for linking between pages.

I am wondering, how do I use the two of them together so that I can get the linking benefits of the Next.js Link component along with the styling benefits of the MaterialUI link component.

Ideally, I'd like to create my own Link component that combines the two of them into my single component so that I can use it anywhere I need to within my project.

Any ideas?

Upvotes: 49

Views: 43475

Answers (14)

Spencer5051
Spencer5051

Reputation: 1085

I disagree with all the accepted answers. This is what I found to be the most succinct and clear.

<Button // MUI Button
  href="/employees"
  LinkComponent={Link} // NextJS Link
>
  Manage Employees
</Button>

This pattern works on most (all?) MUI components.

Upvotes: 35

Hoyeon Kim
Hoyeon Kim

Reputation: 63

Here is my answer. In my case, I wanted to create my 'CustomLink' components in the 'components' folder and export it to wherever I wanted to import and use them.

/components/CustomLink.js

import { Link as MuiLink } from '@mui/material';
import { forwardRef } from 'react';

const CustomLink = forwardRef(({ onClick, href, name }, ref) => {
  return (
    <>
      <MuiLink href={href} onClick={onClick} ref={ref} target='_blank'>
        {name}
      </MuiLink>
    </>
  );
});

export default CustomLink;

then you can use this CustomLink component, such as

/pages/search/[search].js

import Link from 'next/link';
import CustomLink from '@/components/CustomLink';


export default function Search() {
  return(
    <>
      <Link href='your_href_link' passHref legacyBehavior>
        <CustomLink name='read preview' onClick={() => console.log('clicked!')} />
      </Link>
    </>
  );
}

References:

  1. https://nextjs.org/docs/api-reference/next/link
  2. https://mui.com/material-ui/api/link/

Upvotes: 0

Adam
Adam

Reputation: 11

If anyone wants to create custom component here is code

const NextLinkButton = ({ ...props }: Omit<ButtonProps, 'href'> & Pick<LinkProps, 'href'>): JSX.Element => {
      return <Button LinkComponent={Link} {...props} href={props.href.toString()} />;
    };

Upvotes: 0

Amir Mahmoudi
Amir Mahmoudi

Reputation: 429

Updated Answer

Before Next.js 13

import NextLink from 'next/link'
import Link from '@mui/material/Link';

// ...

<NextLink href="/" passHref>
    <Link variant="body2">Your Link</Link>
</NextLink>

From Next.js 13

import NextLink from 'next/link'
import Link from '@mui/material/Link';

<Link href="/" component={NextLink} variant="body2">
  Your link
</Link>

Upvotes: 27

polarchaic
polarchaic

Reputation: 11

for typescript:

import NextLink, { LinkProps } from "next/link";
const LinkBehaviour = forwardRef<HTMLAnchorElement, LinkProps>(
  function LinkBehaviour(props, ref) {
    return <NextLink {...props} />;
  }
);

and bump to @spencer5051's answer

Upvotes: 1

Ali Waqas
Ali Waqas

Reputation: 335

import { useRouter } from "next/router";
import { Button } from "@mui/material";

const router = useRouter();

<Button onClick={() => router.push("/home")}>Home</Button>

This worked for me. The app doesn't refresh either.

Upvotes: -2

atazmin
atazmin

Reputation: 5707

This seem to work for me, using Next with TS, MUi v5

in theme.ts

declare module "@mui/material/Typography" {
  interface TypographyPropsVariantOverrides {
    "button-emphasis": true;
  }
}

...

  const theme = createTheme(theme, {
      components: {
        MuiLink: {
          variants: [
            {
              props: { variant: "button-emphasis" },
              style: {                            
                backgroundColor: darken(theme.palette.blue.main,1),        
                "&:hover": {
                  backgroundColor: darken(theme.palette.blue.main,0.35),
                },
              },
            },
          ],
        },
      },
    });

in component

import NextLink from "next/link";
import { Link } from "@mui/material";

...

<Link component={NextLink} variant="button-emphasis" href="/contact">
Text
</Link>

Upvotes: 1

Shikyo
Shikyo

Reputation: 1685

As of NextJS 13 'next/link' exposes a by default, meaning you no longer have to render an anchor element inside the link component. This makes integration with MUI a lot easier

import { createTheme } from '@mui/material/styles';
import NextLink from 'next/link';
import { forwardRef } from 'react';

const LinkBehaviour = forwardRef(function LinkBehaviour(props, ref) {
    return <NextLink ref={ref} {...props} />;
});

const theme = createTheme({
    components: {
        MuiLink: {
            defaultProps: {
                component: LinkBehaviour
            }
        },
        MuiButtonBase: {
            defaultProps: {
                LinkComponent: LinkBehaviour
            }
        }
    }
});

Then you can import and use '@mui/material/Link' like you do normally.

Alternatively can you set the component when using the link:

<Link component={LinkBehaviour} href="/go-here">
    Click me!
</Link>

There might be some caveats to this approach, so far this is working for me. It also seems to handle external links properly although there might be some overhead there.

Upvotes: 35

juliomalves
juliomalves

Reputation: 50378

Before Next.js 13

You can wrap the Material UI link with the Next.js one. This will provide the benefits of using both.

import NextLink from 'next/link'
import { Link as MUILink } from '@mui/material';

// ...

<NextLink href="/" passHref>
    <MUILink variant="body2">Your Link</MUILink>
</NextLink>

From Next.js 13

See Shikyo's answer for a solution that works with the reworked next/link component in Next.js 13.

Upvotes: 58

The best anwser I found was this

We can create a custom component using Next Link and MUI Link

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>
    );
  }

And then, where you wanna use, you can use like this:

import Link from "../path/to/link";
// Later...
<Link type="button" href="/somewhere">Yay!</Link>

Is the best solution by far...

Credits: codingjlu

Upvotes: 0

kachar
kachar

Reputation: 2548

TypeScript version of the Next.js Link and Material UI Link/Button (v5) with forwardRef can be found at https://gist.github.com/kachar/028b6994eb6b160e2475c1bb03e33e6a

Adding some of the components here for brevity

import React, { forwardRef, Ref } from 'react'
import Link, { LinkProps } from 'next/link'
import { Button, ButtonProps } from '@mui/material'

type LinkRef = HTMLButtonElement
type NextLinkProps = Omit<ButtonProps, 'href'> &
  Pick<LinkProps, 'href' | 'as' | 'prefetch' | 'locale'>

const LinkButton = ({ href, as, prefetch, locale, ...props }: LinkProps, ref: Ref<LinkRef>) => (
  <Link href={href} as={as} prefetch={prefetch} locale={locale} passHref>
    <Button ref={ref} {...props} />
  </Link>
)

export default forwardRef<LinkRef, NextLinkProps>(LinkButton)
import React from "react";
import { Link as LinkMUI, LinkProps as LinkMUIProps } from "@mui/material";
import NextLink, { LinkProps as NextLinkProps } from "next/link";

export type LinkProps = Omit<LinkMUIProps, "href" | "classes"> &
  Pick<NextLinkProps, "href" | "as" | "prefetch">;

export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
  ({ href, as, prefetch, ...props }, ref) => (
    <NextLink href={href} as={as} prefetch={prefetch} passHref>
      <LinkMUI ref={ref} {...props} />
    </NextLink>
  )
);

Upvotes: 1

prakhar tomar
prakhar tomar

Reputation: 1125

To avoid Ref warnings and some errors, I had to do this.

import NextLink from 'next/link';
import { Link as MuiLink } from '@mui/material';

const Link = forwardRef((props: any, ref:any)=>{
  const {href} = props;
  return <NextLink href={href} passHref >
          <MuiLink ref={ref} {...props}/>
          </NextLink>
})
Link.displayName = 'CustomLink';

This is how I used it.

<CardActionArea LinkComponent={Link} href={'/home'}>
...
</CardActionArea>

Upvotes: 7

klevisx
klevisx

Reputation: 182

Had the same problem with the Button component from Material UI. It was not accepting component property because looks like it was not declared. This solved the issue (added component property to the Buton.d.ts): component?: Function;

Here the solution: Buton.d.ts file modified

and boom no error anymore:

Index file no error

Upvotes: -6

Rajiv
Rajiv

Reputation: 3772

Link accepts a component prop that combines both properties. It works perfectly with react-router, might also work well with netxjs Link.

<Link component={NextjsLink}>Link Text</Link>

Here change the import name of the nextjs link.

Related Material-ui Documentation

Upvotes: 13

Related Questions