diff --git a/docs/data/material/guides/routing/routing.md b/docs/data/material/guides/routing/routing.md index c7a1d7cb2430e3..c825977917843d 100644 --- a/docs/data/material/guides/routing/routing.md +++ b/docs/data/material/guides/routing/routing.md @@ -97,53 +97,54 @@ const LinkBehavior = React.forwardRef((props, ref) => ( {{"demo": "ListRouter.js"}} -## More examples - -### Next.js Pages Router - -The [example folder](https://github.com/mui/material-ui/tree/HEAD/examples/material-ui-nextjs-pages-router-ts) provides an adapter for the use of [Next.js's Link component](https://nextjs.org/docs/pages/api-reference/components/link) with Material UI. - -- The first version of the adapter is the [`NextLinkComposed`](https://github.com/mui/material-ui/blob/-/examples/material-ui-nextjs-pages-router-ts/src/Link.tsx) component. - This component is unstyled and only responsible for handling the navigation. - The prop `href` was renamed `to` to avoid a naming conflict. - This is similar to react-router's Link component. - - ```tsx - import Button from '@mui/material/Button'; - import { NextLinkComposed } from '../src/Link'; - - export default function Index() { - return ( - - ); - } - ``` - -- The second version of the adapter is the `Link` component. - This component is styled. - It uses the [Material UI Link component](/material-ui/react-link/) with `NextLinkComposed`. - - ```tsx - import Link from '../src/Link'; - - export default function Index() { - return ( - - Link - - ); - } - ``` +## Next.js + +The example repos provide adapter components for the use of [Next.js's Link component](https://nextjs.org/docs/api-reference/next/link) with Material UI: + +- [Next.js App Router example repo](https://github.com/mui/material-ui/tree/HEAD/examples/material-ui-nextjs-ts) +- [Next.js Pages Router example repo](https://github.com/mui/material-ui/tree/HEAD/examples/material-ui-nextjs-pages-router-ts) + +The first version of the adapter is the [`NextLinkComposed`](https://github.com/mui/material-ui/blob/-/examples/material-ui-nextjs-ts/src/Link.tsx) component. +This component is unstyled and only responsible for handling the navigation. +The `href` prop from Next.js's Link is renamed to `to` in order to distinguish from `@mui/material/Link`'s `href` prop. +The resulting API is similar to react-router's Link component: + +```tsx +import Button from '@mui/material/Button'; +import { NextLinkComposed } from '../src/Link'; + +export default function App() { + return ( + + ); +} +``` + +The second version of the adapter is the `Link` component. +This component is styled. +It uses the [Material UI Link component](/material-ui/react-link/) with `NextLinkComposed`. + +```tsx +import Link from '../src/Link'; + +export default function App() { + return ( + + Link + + ); +} +``` diff --git a/examples/material-ui-nextjs-ts/src/components/Link.tsx b/examples/material-ui-nextjs-ts/src/components/Link.tsx new file mode 100644 index 00000000000000..a456c0d6d50fed --- /dev/null +++ b/examples/material-ui-nextjs-ts/src/components/Link.tsx @@ -0,0 +1,98 @@ +'use client'; +import * as React from 'react'; +import clsx from 'clsx'; +import { usePathname } from 'next/navigation'; +import NextLink, { LinkProps as NextLinkProps } from 'next/link'; +import MaterialLink, { LinkProps as MaterialLinkProps } 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')({}); + +interface NextLinkComposedProps + extends Omit, 'href'>, + Omit { + to: NextLinkProps['href']; + linkAs?: NextLinkProps['as']; +} + +export const NextLinkComposed = React.forwardRef( + function NextLinkComposed(props, ref) { + const { to, linkAs, ...other } = props; + + return ; + }, +); + +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 & + Omit; + +// A styled version of the Next.js Link component: +// https://nextjs.org/docs/app/api-reference/components/link +const Link = React.forwardRef(function Link(props, ref) { + const { + activeClassName = 'active', + as, + className: classNameProp, + href, + linkAs: linkAsProp, + locale, + noLinkStyle, + prefetch, + replace, + role, // Link don't have roles. + scroll, + shallow, + ...other + } = props; + + const routerPathname = usePathname(); + const pathname = typeof href === 'string' ? href : href.pathname; + const className = clsx(classNameProp, { + [activeClassName]: routerPathname === pathname && activeClassName, + }); + + const isExternal = + typeof href === 'string' && (href.startsWith('http') || href.startsWith('mailto:')); + + if (isExternal) { + if (noLinkStyle) { + return ; + } + + return ; + } + + const linkAs = linkAsProp || as; + const nextjsProps = { + to: href, + linkAs, + replace, + scroll, + shallow, + prefetch, + locale, + }; + + if (noLinkStyle) { + return ; + } + + return ( + + ); +}); + +export default Link;