-
-
Save kachar/028b6994eb6b160e2475c1bb03e33e6a to your computer and use it in GitHub Desktop.
| import { LinkProps, Link as MuiLink } from '@mui/material' | |
| import NextLink from 'next/link' | |
| export default function Link(props: LinkProps<'a'>) { | |
| return <MuiLink component={NextLink} {...props} /> | |
| } |
| // Plain JS version + prop-types | |
| // Thanks to @IvanAdmaers | |
| import PropTypes from 'prop-types'; | |
| import { forwardRef } from 'react'; | |
| import NextLink from 'next/link'; | |
| import { Link as MuiLink } from '@material-ui/core'; | |
| const Link = forwardRef(({ href, as, prefetch, ...props }, ref) => { | |
| return ( | |
| <NextLink href={href} as={as} prefetch={prefetch} passHref> | |
| <MuiLink ref={ref} {...props} /> | |
| </NextLink> | |
| ); | |
| }); | |
| Link.displayName = 'Link'; | |
| Link.defaultProps = { | |
| href: '#', | |
| prefetch: false, | |
| }; | |
| Link.propTypes = { | |
| href: PropTypes.string, | |
| as: PropTypes.string, | |
| prefetch: PropTypes.bool, | |
| }; | |
| export default Link; |
| // MaterialUI v4 | |
| import React, { forwardRef, Ref } from 'react' | |
| import Link, { LinkProps } from 'next/link' | |
| import { Link as MuiLink, LinkProps as MuiLinkProps } from '@material-ui/core' | |
| type LinkRef = HTMLAnchorElement | |
| type NextLinkProps = Omit<MuiLinkProps, 'href' | 'classes'> & | |
| Pick<LinkProps, 'href' | 'as' | 'prefetch'> | |
| const NextLink = ({ href, as, prefetch, ...props }: LinkProps, ref: Ref<LinkRef>) => ( | |
| <Link href={href} as={as} prefetch={prefetch} passHref> | |
| <MuiLink ref={ref} {...props} /> | |
| </Link> | |
| ) | |
| export default forwardRef<LinkRef, NextLinkProps>(NextLink) |
| // MaterialUI v5 | |
| // Thanks to @bryantobing12 | |
| 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> | |
| ) | |
| ); |
| // @source https://github.com/mui/material-ui/tree/master/examples/nextjs-with-typescript | |
| // Updated in this gist by @alecriarstudio | |
| import * as React from 'react'; | |
| import clsx from 'clsx'; | |
| import { useRouter } from 'next/router'; | |
| import NextLink, { LinkProps as NextLinkProps } from 'next/link'; | |
| import MuiLink, { LinkProps as MuiLinkProps } from '@mui/material/Link'; | |
| import { styled } from '@mui/material/styles'; | |
| // Add support for the sx prop for consistency with the other branches. | |
| const Anchor = styled('a')({}); | |
| type NextLinkComposedProps = { | |
| to: NextLinkProps["href"]; | |
| linkAs?: NextLinkProps["as"]; | |
| } & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & | |
| Omit<NextLinkProps, "href" | "as">; | |
| export const NextLinkComposed = React.forwardRef<HTMLAnchorElement, NextLinkComposedProps>( | |
| function NextLinkComposed(props, ref) { | |
| const { to, linkAs, replace, scroll, shallow, prefetch, locale, ...other } = props; | |
| return ( | |
| <NextLink | |
| href={to} | |
| prefetch={prefetch} | |
| as={linkAs} | |
| replace={replace} | |
| scroll={scroll} | |
| shallow={shallow} | |
| passHref | |
| locale={locale} | |
| > | |
| <Anchor ref={ref} {...other} /> | |
| </NextLink> | |
| ); | |
| }, | |
| ); | |
| export type LinkProps = { | |
| activeClassName?: string; | |
| as?: NextLinkProps['as']; | |
| href: NextLinkProps['href']; | |
| linkAs?: NextLinkProps['as']; // Useful when the as prop is shallow by styled(). | |
| noLinkStyle?: boolean; | |
| } & Omit<NextLinkComposedProps, 'to' | 'linkAs' | 'href'> & | |
| Omit<MuiLinkProps, 'href'>; | |
| // A styled version of the Next.js Link component: | |
| // https://nextjs.org/docs/api-reference/next/link | |
| const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link(props, ref) { | |
| const { | |
| activeClassName = 'active', | |
| as, | |
| className: classNameProps, | |
| href, | |
| linkAs: linkAsProp, | |
| locale, | |
| noLinkStyle, | |
| prefetch, | |
| replace, | |
| role, // Link don't have roles. | |
| scroll, | |
| shallow, | |
| ...other | |
| } = props; | |
| const router = useRouter(); | |
| const pathname = typeof href === 'string' ? href : href.pathname; | |
| const className = clsx(classNameProps, { | |
| [activeClassName]: router.pathname === pathname && activeClassName, | |
| }); | |
| const isExternal = | |
| typeof href === 'string' && (href.indexOf('http') === 0 || href.indexOf('mailto:') === 0); | |
| if (isExternal) { | |
| if (noLinkStyle) { | |
| return <Anchor className={className} href={href} ref={ref} {...other} />; | |
| } | |
| return <MuiLink className={className} href={href} ref={ref} {...other} />; | |
| } | |
| const linkAs = linkAsProp || as; | |
| const nextjsProps = { to: href, linkAs, replace, scroll, shallow, prefetch, locale }; | |
| if (noLinkStyle) { | |
| return <NextLinkComposed className={className} ref={ref} {...nextjsProps} {...other} />; | |
| } | |
| return ( | |
| <MuiLink | |
| component={NextLinkComposed} | |
| className={className} | |
| ref={ref} | |
| {...nextjsProps} | |
| {...other} | |
| /> | |
| ); | |
| }); | |
| export default Link; |
Thanks for the suggestion @alecriarstudio
I've updated this gist for anyone, but the official version is at https://github.com/mui/material-ui/tree/master/examples/nextjs-with-typescript
You might send a PR to the MUI repo to adapt your suggestion as well.
With the update brought by Next13 we're able to simplify the next/link + mui link/button process a lot:
import { Button, ButtonProps } from '@mui/material'
import NextLink from 'next/link'
export default function LinkButton(props: ButtonProps<'a'>) {
return <Button component={NextLink} {...props} />
}import { LinkProps, Link as MuiLink } from '@mui/material'
import NextLink from 'next/link'
export default function Link(props: LinkProps<'a'>) {
return <MuiLink component={NextLink} {...props} />
}Read more at https://stackoverflow.com/a/74419666/668245
Thanks @kachar
Latest approach is indeed simple but we are not able to pass href as an object. It only accepts string type. Given that NextLink accepts a URL object as href, how can we get same behaviour here?
@vighnesh153 I've tried to make it work with LinkProps['href'] but the MuiButton expectation is a hardcoded { href: string } so I don't think it's currently possible:
// node_modules/@mui/material/Button/Button.d.ts
export type ExtendButton<M extends OverridableTypeMap> = ((
props: { href: string } & OverrideProps<ExtendButtonBaseTypeMap<M>, 'a'>,
) => JSX.Element) &
OverridableComponent<ExtendButtonBaseTypeMap<M>>;What I end up doing in multiple projects is having a general routes.ts file that contains all the app links as follows:
export const routes = {
post: {
byId: (id: string) => `/post/${id}`,
}
}and use it as:
<LinkButton color="secondary" variant="contained" href={routes.post.byId(query.id)}>
View post
</LinkButton>
OfficialLinkMuiv5.tsx
The following 2 errors was displayed at interface NextLinkComposedProps on VSCode
The following are candidates for correction