How to use Nextjs Link with Chakra UI

One of the frequently asked questions on chakra ui library discussions is, How do I use nextjs link with chakra ui button or chakra link? In this post let us explore some common patterns to use nextjs link with chakra.

NextJS provides a Link component out of the box, that can be used for Client-side transitions between different routes. This Link component is exported from next/link package.

What is so special about this component is, it prefetches the linked route by default to provide rapid fast 🚀 page transitions. Until the Link becomes visible to the user, it won't prefetch the route, and once the Link is visible the prefetch is done in the background.

So, to use this component with our design system, we can create a custom component wrapper and make it reusable across the application. Let's see how to do that next.

🚨 From next v13 update, Link component behavior has been updated. Please check the last section of this post for workaround. In short, you would need to pass legacyBehavior prop to make the following tricks work with Chakra UI.

Surround chakra Button with next's Link and provide a passHref prop so that it forwards href to the rendered anchor tag for proper semantics and SEO.

1import Link from "next/link";
2import { Button } from "@chakra-ui/react";
3
4function ChakraNextLinkButton({ href, children, ...props }) {
5 return (
6 <Link href={href} passHref>
7 <Button as="a" {...props}>
8 {children}
9 </Button>
10 </Link>
11 );
12}
13
14function IndexPage() {
15 return (
16 <ChakraNextLinkButton href="/about" colorScheme="facebook">
17 About
18 </ChakraNextLinkButton>
19 );
20}

Notice the as prop in chakra button on line number 7. We are rendering anchor tag instead of button on DOM and applying chakra button styles to it! You can pass all the chakra button props to the component ChakraNextLinkButton like onClick, padding, margin etc.

With this approach, we are following proper web semantics.

We can change the variant prop to 'link' to the same component to render the link styles.

1<ChakraNextLinkButton href="/about" variant="link">
2 About
3</ChakraNextLinkButton>

At the same time, if you want to have control over next's Link via props, you would need to separate the props in the custom component and pass it appropriately like below

1import Link from "next/link";
2import { Button } from "@chakra-ui/react";
3
4function ChakraNextLinkButton({ href, children, prefetch = true, ...props }) {
5 return (
6 <Link href={href} passHref prefetch={prefetch}>
7 <Button as="a" {...props}>
8 {children}
9 </Button>
10 </Link>
11 );
12}
13
14function IndexPage() {
15 return (
16 <ChakraNextLinkButton
17 href="/about"
18 colorScheme="facebook"
19 prefetch={false}>
20 About without prefetch
21 </ChakraNextLinkButton>
22 );
23}

See more about Next's Link props in next's documentation about Link component

If we want to use Chakra's Link with Next's Link, we can do that easily by this method.

1import Link from "next/link";
2import { Link as ChakraLink } from "@chakra-ui/react";
3
4function ChakraNextLink({ href, children, ...props }) {
5 return (
6 <Link href={href} passHref>
7 <ChakraLink {...props}>{children}</ChakraLink>
8 </Link>
9 );
10}
11
12function IndexPage() {
13 return (
14 <ChakraNextLink href="https://bharathikannan.com" isExternal color="red">
15 Visit my homepage
16 </ChakraNextLink>
17 )
18}

Notice that we can pass isExternal prop to the custom component, and that would forward the prop to Chakra's Link component to add the target="_blank" and rel="noopener noreferrer" attributes to rendered HTML automatically.

Usage with Typescript#

If you are using next js with typescript and if you want to make use of typescript intellisense, code completion and static type checking for our custom chakra components, you can create a new prop type by merging Chakra's Props and Next's Props and provide it to our component like below

1import Link, { LinkProps } from "next/link";
2import {
3 Button,
4 ButtonProps,
5} from "@chakra-ui/react";
6
7type ChakraAndNextProps = ButtonProps & LinkProps;
8
9function ChakraNextLinkButton({
10 href,
11 children,
12 prefetch = true,
13 ...props
14}: ChakraAndNextProps) {
15 return (
16 <Link href={href} passHref prefetch={prefetch}>
17 <Button as="a" {...props}>
18 {children}
19 </Button>
20 </Link>
21 );
22}
23
24function IndexPage() {
25 return (
26 <ChakraNextLinkButton href="/about" colorScheme="facebook">
27 About
28 </ChakraNextLinkButton>
29 );
30}

Wow! Now we got code completion with static props checking!

And for the Chakra Link,

1import Link, { LinkProps } from "next/link";
2import {
3 Link as ChakraLink,
4 LinkProps as ChakraLinkProps,
5} from "@chakra-ui/react";
6
7type ChakraLinkAndNextProps = ChakraLinkProps & LinkProps;
8
9function ChakraNextLink({ href, children, ...props }: ChakraLinkAndNextProps) {
10 return (
11 <Link href={href} passHref>
12 <ChakraLink {...props}>{children}</ChakraLink>
13 </Link>
14 );
15}
16
17
18function IndexPage() {
19 return (
20 <ChakraNextLink href="https://bharathikannan.com" isExternal color="red">
21 Visit my homepage
22 </ChakraNextLink>
23 );
24}

Great! Now we won't be missing Chakra's prop intellisense!

Note: In the above examples, you are responsible for separating chakra props and next props and passing it to the corresponding components!

Bonus Tip#

You can shorten the prop spreading on components without mentioning children

1// BEFORE
2function ChakraNextLinkButton({ href, children, prefetch = true, ...props }) {
3 return (
4 <Link href={href} passHref prefetch={prefetch}>
5 <Button as="a" {...props}>
6 {children}
7 </Button>
8 </Link>
9 );
10}
11
12// AFTER
13function ChakraNextLinkButton({ href, prefetch = true, ...props }) {
14 return (
15 <Link href={href} passHref prefetch={prefetch}>
16 <Button as="a" {...props} />
17 </Link>
18 );
19}

Next 13 Update#

In the new version of next v13, Link component behaviour has been updated, now it doesn't allow the child to be a tag. In order to make the above tricks work, you would need to pass additional prop legacyBehavior to the Link component.

1import Link from "next/link";
2import { Button } from "@chakra-ui/react";
3
4function ChakraNextLinkButton({ href, children, ...props }) {
5 return (
6 <Link href={href} passHref legacyBehavior>
7 <Button as="a" {...props}>
8 {children}
9 </Button>
10 </Link>
11 );
12}
13
14function IndexPage() {
15 return (
16 <ChakraNextLinkButton href="/about" colorScheme="facebook">
17 About
18 </ChakraNextLinkButton>
19 );
20}

At the time of writing this post, Chakra has just included their own next integration for Link component to support Next v13 updates. View their documentatiom on using the same: Chakra UI with Next.js Link. To note this new component integration has some open issues, so please read carefully before using it. View the issue ESM Import Error in chakra next link

Here is the sandbox link for all the above examples to see it live ✅

Do you think anything else to be added? Did you notice any issues in the post? Let me know at my Twitter handle, or please feel free to submit a PR to edit this post! There should be an Edit this Post link below 😀


References


Published:September 4, 2021

Updated:June 10, 2024