DEV Community

Cover image for How to add canonical url to Remix 💿
Can Rau
Can Rau

Posted on • Originally published at canrau.com

How to add canonical url to Remix 💿

This article has originally been published to canrau.com

Using loader data

This one is probably my fav, as it doesn't require any other function than the most probably already present loader. And because it's part of the loader it gives me full access to the already fetched content 🥰

import { homepage } from "/package.json"; // or import from some kind of "/config"
export const loader: LoaderFunction = async ({ params }) => {
  // [..]
  const { frontmatter, code } = await bundleMDX();
  // [..]
  const canonical = `${homepage}/${frontmatter?.lang}${frontmatter?.slug}`;
  return { frontmatter, code, canonical };
};
Enter fullscreen mode Exit fullscreen mode

Then in my root.tsx I have the following Document component, where especially lines 12 - 14 and line 23 are relevant.

function Document({
  children,
  title,
  lang,
}: {
  children: ReactNode;
  title?: string;
  lang: string;
}) {
  // use `export const handle = { hydrate: true };` in any route to enable JS
  const includeScripts = useShouldHydrate(); // from remix-utils
  const matches = useMatches();
  const match = matches.find((match) => match.data && match.data.canonical);
  const canonical = match?.data.canonical;

  return (
    <html lang={lang} className="dark scroll-smooth">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        {title ? <title>{title}</title> : null}
        <Meta />
        {!!canonical && <link rel="canonical" href={canonical} />}
        <Links />
        <link
          rel="alternate"
          type="application/rss+xml"
          href={`${rootUrl}/${lang}/feed.xml`}
          title="Can Rau's XML Feed"
        />
        <link
          rel="alternate"
          type="application/feed+json"
          href={`${rootUrl}/${lang}/feed.json`}
          title="Can Rau's JSON Feed"
        />
      </head>
      <body className="dark:bg-gray-900">
        {children}
        <ScrollRestoration />
        {includeScripts && <Scripts />}
        {process.env.NODE_ENV === "development" && <LiveReload />}
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

Note: More about the <link rel="alternate" /> in my other article RSS in Remix

More about useMatches in the Remix Package docs and in the Disabling Javscript docs

Remix used to provide the loader data to links, but they had to remove it for prefetching

Related links

Top comments (0)