Reputation: 7007
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
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
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:
Upvotes: 0
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
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
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
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
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
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
Reputation: 50378
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>
See Shikyo's answer for a solution that works with the reworked next/link
component in Next.js 13.
Upvotes: 58
Reputation: 1
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
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
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
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;
and boom no error anymore:
Upvotes: -6
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