How to Compose Next 13 Link and MUI Link (with Typescript)
Jasser Mark Arioste
Hello, hustler! NextJS recently released a major update which is Next 13, It included an update to the critical next/link
component. In this tutorial, you'll learn how to customize the MUI Link
component and integrate the behavior of the next/link
component and fix the naming conflict of the href
prop of both components.
Introduction #
NextJS and MUI are a very common combination for front-end development and it speeds up the development time by a lot. When NextJS released version 13, I found it difficult to customize the MUI Link
with next/link
. I was able to figure out two ways to achieve the desired behavior.
The techniques shown here can be used not only for the next/link
component but when creating any other custom components as well.
Scope of this Tutorial #
We limit this tutorial to the following versions:
- MUI version 5.x and up
- NextJS version 13.x and up
Way #1 - Using the component
Property of MuiLink
#
If you don't need to create a custom component you can directly use the component
property of MuiLink, but it's not without its drawbacks. For example:
import { Link as MuiLink } from "@mui/material"; import NextLink from "next/link"; const Container = () => { return ( <div> {/* This will use "prop forwarding" and MuiLink will automatically have the props of NextLink */} <MuiLink component={NextLink} prefetch={false} href={"/page1"}> hello </MuiLink> {/* However, passing a URLObject in href results in a type error */} <MuiLink component={NextLink} prefetch={false} href={{ pathname: "/page1" }} //type error > hello </MuiLink> </div> ); }; export default Container;
123456789101112131415161718192021
This pattern will use prop forwarding and MuiLink
will automatically get the NextLink
props. But since both MuiLink
and NextLink
have href
props, this causes name collisions and results in a type error. It will use the href
prop from MuiLink
.
Way #2 - Modifying NextLink
href
Property
#
To solve the problem above, you can extend the NextLink
component and rename the href
prop to something else to avoid naming collisions. Here's how to do it in Typescript.
// components/MyLink.tsx import { LinkProps, Link as MuiLink } from "@mui/material"; import NextLink, { LinkProps as NextLinkProps } from "next/link"; // Defining the CustomNextLink export type CustomNextLinkProps = Omit<NextLinkProps, "href"> & { _href: NextLinkProps["href"]; }; export const CustomNextLink = ({ _href, ...props }: CustomNextLinkProps) => { return <NextLink href={_href} {...props} />; }; // combine MUI LinkProps with NextLinkProps type CombinedLinkProps = LinkProps<typeof NextLink>; // remove both href properties // and define a new href property using NextLinkProps type MyLinkProps = Omit<CombinedLinkProps, "href"> & { href: NextLinkProps["href"]; }; const MyLink = ({ href, ...props }: MyLinkProps) => { // use _href props of CustomNextLink to set the href return <MuiLink {...props} component={CustomNextLink} _href={href} />; }; export default MyLink;
12345678910111213141516171819202122
Explanation:
Line 5-10: We define the component CustomNextLink that uses _href
prop to avoid naming collisions. This is an internal component for this file and is not to be used anywhere else.
Line 12-17: We take a roundabout way to remove the href
props and define a new href
prop that uses the one NextLinkProps
for our custom MuiLink
component.
Line 20: Here's where the magic happens. We use the _href
props from our CustomNextLink
and pass the next href
prop that we just defined on line 16.
Perhaps there's a better way of defining the MyLinkProps
, but I found this to be really easy to digest.
Usage:
import MyLink from "./MyLink"; // MyLink usage const Container2 = () => { return ( <div> <MyLink prefetch={false} scroll={false} sx={{ color: "warning.main" }} href={{ pathname: "/page1" }} > hello </MyLink> <MyLink prefetch={false} scroll={false} sx={{ color: "warning.main" }} href="/page2" //Both string and URLObject are accepted > hello </MyLink> </div> ); }; export default Container2;
12345678910111213141516171819202122232425
Here we can see that it's a very seamless integration with NextLink
and MUILink
. I think this is a very good pattern to know.
Usage with styled
:
If you want to use styled components, you can use the new wrapper component as the base:
// components/StyledLink: import { styled } from "@mui/material/styles"; import MyLink, { MyLinkProps } from "./MyLink"; const StyledLink = styled(MyLink)<MyLinkProps>({}); StyledLink.defaultProps = { color: "seagreen", underline: "hover", }; export default StyledLink;
12345678910
Full Code #
The full code can be accessed at Github: Next Link with MUI Link Tutorial
Conclusion #
We learned how to integrate next/link
with MUI Link
component by creating a custom component and modifying the default props to avoid naming collisions. I think this is a very important pattern to learn and master, and you can apply it in other MUI components as well.
If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on Twitter.
Credits: Image by Karl Egger from Pixabay