There's plenty of information about how to use Next.js' Link
module if the child itself has an <a>
tag within it (passHref
), but there seems to be no indication that this should be needed for child component that aren't creating their own <a>
tag. But I have run into a situation where a "decorator" component being a child of a Link
component causes the link to not get rendered at all.
import React from 'react'
import Link from 'next/link'
import type { NextPage } from 'next'
interface Props {
children: string
}
// A simple functional component that transforms its child to more readable form
const HexString = ({ children: hex }: Props) => {
const shortHex = hex.substring(0, 8) + '...' + hex.substring(hex.length - 6)
return (
<span title={hex} className="hex-string">
{shortHex}
</span>
)
}
// Page component wishing to use that decorator inside a Link
const MyPage: NextPage = () => {
return (
<div>
<Link href="/index">
<HexString>0x0102030405060708090a0b0c0d0e0f</HexString>
</Link>
</div>
)
}
export default MyPage
What gets rendered to the page is only the hex-string
span and its contents. The <a>
tag the Link
is supposed to add is not in the DOM.
How can I get the Link
component to properly render an anchor tag around this styled span tag from another component?
This is a difference in behavior between Next.js v12 and v13. Details about this change are in https://github.com/vercel/next.js/pull/36436. This is not yet in the documentation because it's an "experimental" feature)
In versions 12 and less, the behavior was to not include a literal anchor tag for Link
:
// Renders: <strong onClick={nextLinkClickHandler}>Hello</strong>. No `<a>` is included.
<Link href="/about">
<strong>Hello</strong>
</Link>
// Renders: <strong onClick={nextLinkClickHandler}>Hello</strong>. No `<a>` is included.
<Link href="/about">
<CustomComponent />
</Link>
Note this happens when the child of a Link
component is either a custom component (as this question shows) or an HTML tag.
In Next.js v13, this will be changing to always render an <a>
anchor tag wrapped around those child components.
In Next.js v12, that behavior can be opted-into by setting the experimental.newNextLinkBehavior
flag.
So, to ensure that an anchor tag is always present, either set experimental.newNextLinkBehavior
to true (if using Next.js v12), or add an empty <a>
tag around the child component:
// Page component wishing to use that decorator inside a Link
const MyPage: NextPage = () => {
return (
<div>
<Link href="/index">
<a><HexString>0x0102030405060708090a0b0c0d0e0f</HexString></a>
</Link>
</div>
)
}