Sitecore JSS Link IS Next.js Link.
Sitecore JSS Link is an expansion of the Next.js Link. The main difference is that the JSS Component checks if the link is internal/external and renders using the Next.js Link component (next/link
) or a normal link component (<a>
).
Next.js Link/JSS vs <a>
Next.js Links benefits are for Internal linking, and is mainly used for preloading data. That said, the Next.js link also handles external links without any issues.
Page preloading happens when the next <Link />
component enters the user's viewport (similar to how animations work, think intersection observer). Next.js will automatically prefetch the data from the internal link and load the linked page. This is done in the background with the goal of improving client-side navigation performance.
Note: Prefetching is only enabled in production.
Sitecore JSS Next.js SDK Link Component in Sitecore Edit Mode:
JSS Next.js SDK Link
component: In normal mode returns a next/Link
component. You control prefetch like on the next/Link
component. In edit mode returns a JSS React SDK Link
component.
JSS React SDK Link
component: In edit mode returns an editable <span>
with or without a simple <a>
inside. This does not have prefetch functionality.
Conclusion: Prefetching cannot be the cause of performance issues in Experience Editor or Pages when using SSR.
How Next.js Link Works
Next <Link>
is a stock React component built by Next.js that builds upon the standard HTML <a>
element to provide native prefetching for client-side navigation. Hence, it closely resembles the native <a>
element but provides extra advantages such as customizable navigation behavior via props, enhanced performance, and SEO benefits.
Next.js Link Parameters and When To Use Them
Prop | Example | Type | Description |
---|---|---|---|
href | href="/dashboard" | String / Object | String or object that points to the desired location. The object can be used to pass query string data (URL) |
prefetch | prefetch={false} | Boolean | Should the link be preloaded when entering the user's viewport. False = preload on link hover. |
replace | replace={false} | Boolean | Used to replace the browsers current history state instead of adding a new URL to the browser's history. |
scroll | scroll={false} | Boolean | Used to scroll the user to the top of the page on a new page route, and maintain scroll position on forwards/backwards navigation |
passHref | passHref={true} | Boolean | Forces Link to send the href property to its child. Defaults to false |
shallow | shallow={true} | Boolean | Update the path of the current page without rerunning getStaticProps, getServerSideProps or getInitialProps. Defaults to false |
locale | locale=”en” | String | The active locale is automatically prepended. locale allows for providing a different locale. When false href has to include the locale as the default behavior is disabled. |
How To Configure Next.js Link
Legacy Link: Next.js 12.X and Under
The legacy link required an <a>
tag to be nested inside the <Link>
tag. You could then apply all properties (ex: onClick
, ClassName
) to the <a>
tag directly.
Using passHref
was also a requirement for legacy links, otherwise the href wouldn't be passed to the <a>
tag, and it would be a JS only route change.
Example of Legacy Code you might see in older projects
<Link href="/posts/[post]" scroll={false} passHref prefetch={false}>
<a className="bg-primary p-8 rounded" onClick={()=> alert("Click")}>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Odit deleniti qui nobis
minima eaque, hic praesentium tempora optio perspiciatis perferendis soluta labore
esse mollitia ipsam reprehenderit tenetur? Molestiae, laboriosam assumenda.
</a>
</Link>
New Next.js Link: Next.js 13.X and Up
This is the currently used Link tag by Next.js and Sitecore JSS. The main difference is the removal of the nested <a>
tags and passHref
no longer being required.
<Link
href="/posts/[post]"
scroll={false}
prefetch={false}
className="bg-primary p-8 rounded"
onClick={() => alert('Click')}
>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Odit deleniti qui nobis
minima eaque, hic praesentium tempora optio perspiciatis perferendis soluta labore
esse mollitia ipsam reprehenderit tenetur? Molestiae, laboriosam assumenda.
</Link>
When To Enable Next Preloading/Prefetching
Link preloading/prefetching is one of the reasons Next.js feels so fast as a user. However, Next.js will try to immediately preload all links that are in the user's viewport. This can slow down initial page loads, subsequent dynamically imported components and lazy loaded images.
You can't actually disable prefetching. You can only toggle between two modes:
- Prefetch upon entering Viewport
- Prefetch upon user hovering over the link (
prefetch={false}
)
If you want to avoid preloading all together, you would use a native <a>
tag, although this would only be relevant in very niche use cases, and is not recommended. A plain <a>
will do a full page refresh and reload the entire Next.js/React app. A next/link with prefetch={false}
will do an XHR to load the target page JSON file and update the DOM using React's Shadow DOM and will be significantly faster!
<Link
prefetch={false}
... >
Generally, we only want viewport preloading for high traffic links, and large real estate links.
Examples:
- High traffic pages in the nav bar
- Hero banner links (CTA’s)
- Featured article links
Preloading/Prefetching Case Study
For example: The above the fold on this website’s homepage has ~41 total links:
- 11 Links in the nav
- 4 Link Dropdowns in the Nav (each containing more links)
- 9 Sub nav links
- 7 Articles presented to the user (Each one is a link)
- 14 sub link, inside the article links (Topics & Authors)
We want to optimize this for the user to prevent their browser from immediately loading ~41 different links! We want to “Preload on Hover” for almost all the links on this page. There are only a few potential candidates for preloading in the view port. You want to preload the links that have large real estate (massive featured article) and URLs with a high click-through rate (~25%+).
In the below image, I suggest the few links that I think could be candidates for “Preload in Viewport”.
Image Key:
- Potential candidates for Preload in Viewport = Red
- Preload on Hover = Yellow & Green
In the above image I am assuming that one of the two navigation links (Artificial Intelligence, Cryptocurrency) have a high click-through rate, and I'm recommending that they preload them for the user. However, it is very realistic that the only “Preload in Viewport” item on the page would be the massive-featured article.
You should use “Preload in Viewport” sparingly, as it will put more load on both your servers and the user's computer. It's more efficient to default to only preloading on hover for most of your links.
When Not to Use a JSS Link
You should only use the native Next.js link if you don't have all the LinkField
data. A good example of this is linking to social media sites.
Example:
<div>
<NextLink
href={`https://twitter.com/intent/tweet?text=${socialPageTitle}+-+${currentUrl}`}
target="_blank">
<SvgTwitter />
</NextLink>
</div>
How to Use Both JSS and Next.js/Link at the Same Time
Sometimes you will have 2 different links, one that is a full LinkField
, and another that is only a URL. You can't naturally import both at the same time, since they both have the same component name. You can use a simple alias import to import the default Next.js link under a different name.
import { default as NextLink } from 'next/link';
import { Link } from '@sitecore-jss/sitecore-jss-nextjs';
...
<NextLink
href={</span><span class="hljs-attr"><span class="hljs-tag"><span class="hljs-attr">https:</span></span></span><span class="hljs-tag">//</span><span class="hljs-attr"><span class="hljs-tag"><span class="hljs-attr">twitter.com</span></span></span><span class="hljs-tag">/</span><span class="hljs-attr"><span class="hljs-tag"><span class="hljs-attr">intent</span></span></span><span class="hljs-tag">/</span><span class="hljs-attr"><span class="hljs-tag"><span class="hljs-attr">tweet</span></span></span><span class="hljs-tag">?</span><span class="hljs-attr"><span class="hljs-tag"><span class="hljs-attr">text</span></span></span><span class="hljs-tag">=</span></span></span><span class="hljs-subst"><span class="hljs-string"><span class="hljs-subst"><span class="hljs-tag"><span class="hljs-string"><span class="hljs-tag"><span class="hljs-string">${socialPageTitle}</span></span></span></span></span></span></span><span class="hljs-string"><span class="hljs-tag"><span class="hljs-string"><span class="hljs-tag"><span class="hljs-string">+-+</span></span></span></span></span><span class="hljs-subst"><span class="hljs-string"><span class="hljs-subst"><span class="hljs-tag"><span class="hljs-string"><span class="hljs-tag"><span class="hljs-string">${currentUrl}</span></span></span></span></span></span></span><span class="hljs-string"><span class="hljs-tag">
}
target="_blank">
<SvgTwitter />
</NextLink>
<Link
field={props.fields?.link}
className="font-semibold text-primary underline text-2xl px-sm py-xs border rounded"
/>