Skip to content

Instantly share code, notes, and snippets.

@herr-vogel
Last active November 16, 2021 10:14
Show Gist options
  • Select an option

  • Save herr-vogel/0b5d4f3c28f08dc6cc4a2fd4f7b4a4df to your computer and use it in GitHub Desktop.

Select an option

Save herr-vogel/0b5d4f3c28f08dc6cc4a2fd4f7b4a4df to your computer and use it in GitHub Desktop.
Using Material-UI Button with Next.js Link
import React from 'react'
import Link from 'next/link'
import Button from '@material-ui/core/Button'
const ButtonLink = ({ className, href, hrefAs, children, prefetch }) => (
<Link href={href} as={hrefAs} prefetch>
<a className={className}>
{children}
</a>
</Link>
)
// https://material-ui.com/demos/buttons/#third-party-routing-library
const RenderButton = () => <Button component={ButtonLink} href={'/foo'}>bar</Button>
@leomelzer

Copy link
Copy Markdown

Thanks @andfk and others, this works perfectly! ๐Ÿ’ฏ

I apply it like this for example:

<Chip
	label={myLabel}
	component={ButtonLink}
	href="/some/[link]"
	as={`/some/${encodeURIComponent(link)}`}
	clickable
/>

@dohomi

dohomi commented Oct 31, 2019

Copy link
Copy Markdown

Is it not sufficient to use the passHref prop from nextjs/link? Just asking for the opinion because I would think this should work:

import React from "react";
import Link from "next/link";
import Button from "@material-ui/core/Button";

export default ButtonLink = () => (
  <Link href="/pricing" passHref>
    <Button component="a">Button Link</Button>
  </Link>
);

@leomelzer

Copy link
Copy Markdown

@dohomi Great! Yeah I think that is the main idea and should work! @andfk's example provides reliable types (TS) and allows to pass in other related props, too. Hope that helps!

@sushilbansal

sushilbansal commented Jan 4, 2020

Copy link
Copy Markdown

@leomelzer, @andfk, should not <Button be sorrounded by <a tag?

@leomelzer

Copy link
Copy Markdown

Hi @sushilbansal,

@leomelzer, @andfk, should not <Button be sorrounded by <a tag?

Hm, <Link> in <ButtonLink> will output an a tag. Doesn't the solution work for you? Maybe you can share a bigger snippet.

@arieu

arieu commented Jan 10, 2020

Copy link
Copy Markdown

@fev4

fev4 commented Feb 5, 2020

Copy link
Copy Markdown

@iz-ben @leomelzer @andfk Thanks for the great suggestions.

I got a warning with StrictMode:

Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of Link which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://fb.me/react-strict-mode-find-node
    in a (at ButtonLink.js:11)
    in Link (at ButtonLink.js:10)
    in ButtonLink (created by ForwardRef(ButtonBase))
    in ForwardRef(ButtonBase) (created by WithStyles(ForwardRef(ButtonBase)))
    in WithStyles(ForwardRef(ButtonBase)) (created by ForwardRef(Button))
    in ForwardRef(Button) (created by WithStyles(ForwardRef(Button)))
    in WithStyles(ForwardRef(Button)) (created by ButtonLink___StyledButton)
    in ButtonLink___StyledButton (at ButtonLink.js:19)
    in RenderButton (at NavBar.js:106)
    in div (created by ForwardRef(Toolbar))
    in ForwardRef(Toolbar) (created by WithStyles(ForwardRef(Toolbar)))
    in WithStyles(ForwardRef(Toolbar)) (at NavBar.js:86)
    in header (created by ForwardRef(Paper))
    in ForwardRef(Paper) (created by WithStyles(ForwardRef(Paper)))
    in WithStyles(ForwardRef(Paper)) (created by ForwardRef(AppBar))
    in ForwardRef(AppBar) (created by WithStyles(ForwardRef(AppBar)))
    in WithStyles(ForwardRef(AppBar)) (created by NavBar__NavContainer)
    in NavBar__NavContainer (at NavBar.js:85)
    in div (at NavBar.js:84)
    in NavBar (at PageLayout.js:58)
    in UserProvider (at PageLayout.js:52)
    in StylesProvider (at PageLayout.js:51)
    in ThemeProvider (at PageLayout.js:50)
    in StrictMode (at PageLayout.js:43)
    in PageLayout (at HomeLayout.js:7)
    in HomeLayout (at pages/index.js:44)
    in Home (at apollo.js:29)
    in ApolloProvider (at apollo.js:28)
    in withApollo(Home) (at _app.js:24)
    in ThemeProvider (at _app.js:23)
    in WagglioMainApp
    in Container (created by AppContainer)
    in AppContainer

This is the code used:

const ButtonLink = React.forwardRef(
  ({ className, href, hrefAs, children }, ref) => (
    <Link href={href} as={hrefAs} ref={ref}>
      <a>{children}</a>
    </Link>
  )
);

ButtonLink.displayName = 'ButtonLink';

const RenderButton = ({ children, contrast, ...otherProps }) => (
  <Button
    {...otherProps}
    component={ButtonLink}
    css={[
      css`
        &.MuiButton-root {
          ${tw`rounded-2xl`}
        }
      `,
      otherProps.color === 'primary' &&
        contrast &&
        css`
          &.MuiButton-containedPrimary {
            ${tw`bg-white text-cyan-500 font-bold`}
          }
        `,
    ]}
  >
    {children}{' '}
  </Button>
);
RenderButton.propTypes = {
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
};

export default RenderButton;

Is there a way to avoid this warning besides simply deactivating it? Any comments are appreciated.

@adir1661

Copy link
Copy Markdown

I still didnt understand how to apply it....
i mean i want to use the 'as' property, but where should i put it in the above exmaple...
i do not use typescript...

@josephshambrook

Copy link
Copy Markdown

If you're here for a quick solution as of 2020-05-01:

  1. Go straight to Material UI's Next.js example project on GitHub. There's a Link.js component that is well developed and flexible, and worked for me without having to make additional changes. Copy that and add it to your repo.

  2. Once copied and imported (i.e. import Link from '../wherever/you/added/it/Link), here's how to use it:

  • As a bog standard link:
      <Link href="/about">
        About
      </Link>
    
  • As a button:
      <Button component={Link} href="/about">
        About
      </Button>
    
  • As a list item:
      <ListItem button component={Link} href="/about">
        <ListItemText primary="About" />
      </ListItem>
    

@kenberkeley

Copy link
Copy Markdown

@LoicHa

LoicHa commented May 7, 2020

Copy link
Copy Markdown

@josephshambrook thank you so much

@kamrankhanwastaken

Copy link
Copy Markdown

How can I change a Button component's properties like color and variant based on the active class here? A little stuck! :(

@girishbin

Copy link
Copy Markdown

https://github.com/mui-org/material-ui/blob/4b6cbf0/examples/nextjs-with-typescript/src/Link.tsx

This is very useful , we can pass material UI styles to next.js link

@wguerram

wguerram commented Jun 8, 2020

Copy link
Copy Markdown

@kenberkeley thanks for sharing.

How could I get rid of the hover underline in the button text when used this way?
<Button color="inherit" component={Link} href="/about"> About </Button>

@kenberkeley

Copy link
Copy Markdown

@wguerram text-decoration: none?

@wguerram

wguerram commented Jun 8, 2020

Copy link
Copy Markdown

@wguerram text-decoration: none?

Thanks @kenberkeley

<Button color="inherit" style={{ textDecoration: 'none' }} component={Link} href="/about">
About
</Button>

@Luis-Enrique1

Copy link
Copy Markdown

it worked so well.... thanks a lot man

@daveteu

daveteu commented Jun 11, 2020

Copy link
Copy Markdown

nobody got the forwardRef error?
https://material-ui.com/guides/composition/#caveat-with-refs

Working code with forwardRef

import React , { forwardRef } from 'react'
import Link from 'next/link'
import Button from '@material-ui/core/Button'


const ButtonLink = forwardRef( ({ className, href, as, children, prefetch }, ref)=> (
  <Link href={href} as={as} prefetch ref={ref}>
    <a className={className}>
      {children}
    </a>
  </Link>
))

@sajadghawami

Copy link
Copy Markdown

If you're here for a quick solution as of 2020-05-01:

  1. Go straight to Material UI's Next.js example project on GitHub. There's a Link.js component that is well developed and flexible, and worked for me without having to make additional changes. Copy that and add it to your repo.
  2. Once copied and imported (i.e. import Link from '../wherever/you/added/it/Link), here's how to use it:
  • As a bog standard link:
      <Link href="/about">
        About
      </Link>
    
  • As a button:
      <Button component={Link} href="/about">
        About
      </Button>
    
  • As a list item:
      <ListItem button component={Link} href="/about">
        <ListItemText primary="About" />
      </ListItem>
    

Thanks man! <3

@GhazanfarKhan

Copy link
Copy Markdown

const ButtonLink = React.forwardRef(({ className, href, hrefAs, children, prefetch }, ref) => (


{children}


));

Thanks it worked in latest version.

@dohomi

dohomi commented Jun 20, 2020

Copy link
Copy Markdown

Instead of overwriting textDecoration on buttons I guess set prop naked:true will prevent to interfer with styles of MuiLink on the components

@onepixelsolid

Copy link
Copy Markdown

I encountered the issue mentioned here Caveat with refs and fixed it by making the following changes to your code.

Hope it helps someone

const ButtonLink = React.forwardRef(({ className, href, hrefAs, children, prefetch }, ref) => (
    <Link href={href} as={hrefAs} prefetch ref={ref}>
        <a className={className}>
            {children}
        </a>
    </Link>
));

Yes! This fixed my ref warnings.

@ats1999

ats1999 commented Oct 10, 2020

Copy link
Copy Markdown

Thank you!

Next.js auto-prefetches automatically based on viewport. The prefetch attribute is no longer needed. More: https://err.sh/vercel/next.js/prefetch-true-deprecated

@ats1999

ats1999 commented Oct 10, 2020

Copy link
Copy Markdown

All the above examples are not using client-side routing.

@Guneetgstar

Copy link
Copy Markdown

Why so much discussion over it? Is there something wrong with this:

import RLink from 'next/link'
import {Link} from "@material-ui/core";

<RLink href={"/privacy"} passHref>
   <Link>
         Privacy Policy
   </Link>
</RLink>

@ats1999

ats1999 commented Nov 4, 2020

Copy link
Copy Markdown

You don't need to wrap Link with RLink.
RLink is alone enough to handle routing.

@Guneetgstar

Guneetgstar commented Nov 4, 2020

Copy link
Copy Markdown

@ats1999 Yeah sure I did that for styling the subcomponets as I don't want to write custom css ๐Ÿ˜‰
And another pros for adding link is that Link wraps the children inside <a> tag which is a requirement for me(for better SEO) and that's why you can see passHref prop in RLink tag.
Most importantly the purpose of this whole thread is to use Link with RLink so thats what I did and shared.

@ats1999

ats1999 commented Nov 4, 2020

Copy link
Copy Markdown

Ohh!

@kachar

kachar commented Feb 3, 2021

Copy link
Copy Markdown

One more wrapper for both Link and Button components can be found here (typescript version) https://gist.github.com/kachar/028b6994eb6b160e2475c1bb03e33e6a

@EddyVinck

Copy link
Copy Markdown

I had a ref error for my wrapped Material UI Button in a NextJS Link, which is what I was searching for when I found this thread. I didn't need any of the above, except wrapping my button with React.forwardRef

import { makeStyles } from "@material-ui/core/styles";
import { Button as MuiButton, ButtonProps } from "@material-ui/core";

const useStyles = makeStyles((theme) => ({
  root: {
    // your styles
  },
}));

interface Props extends ButtonProps {}

export const Button: React.FC<Props> = React.forwardRef((props, ref) => {
  const classes = useStyles();

  return <MuiButton ref={ref} className={classes.root} {...props} />;
});
Button.displayName = "Button";

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment