Using linkResolver in Rich Text

Hi,

I am having troubles understanding and implementing linkResolver.

I have two single Custom Types: Homepage and About.

The About page has a UID of about

I am trying to create a link within a Rich Text field from the Homepage to the About page.

The query to the link looks like this:

On the Homepage, my code is the following:

<RichText htmlSerializer={htmlSerializer} serializeHyperlink={CustomLink} render={doc.lede.raw} />

This is the code in the CustomLink component:

import React from 'react'
import { Link } from 'gatsby'
import { linkResolver } from './LinkResolver'

export const CustomLink = (type, element, content, children, index) => {
  if (element.data.link_type === 'Document') {
    <Link to={linkResolver(element.data)} key={element.data.id}>
      {content}
    </Link>
  }

  if (element.data.link_type === 'Web') {
    <a id={element.data.id} href={element.data.url}>
      {content}
    </a>
  }
  return null
}

And this is the code in the linkResolver component

exports.linkResolver = (doc) => {
  if (doc.type === 'about') {
    return `/${doc.uid}`
  }

  return '/'
}

Unfortunately I am unable to get the link to route to the About page. Could I please get some advice on this?

Thank you!

Hello @hon.boey

Welcome to the Prismic community.

I assume you save the response from a query in a variable called `doc. In that case, the Rich Text render method should be:

<RichText render={doc.data.lede.raw} />

As explained in this article, have you registered link resolver to the plugin?

Let me know if it still doesn't solve your issue. I'd be happy to dig it more.

Thanks,
Priyanka

Hi Priyanka,

Thanks for getting back to me.

The variable doc is defined as data.prismicHomepage.data. The RichText function is rendering my text so I know that the doc.lede.raw query in the follwing is correct:

<RichText htmlSerializer={htmlSerializer} serializeHyperlink={CustomLink} render={doc.lede.raw} />

Also, I have registered the linkResolver to the plugin as shown below:

{
      resolve: `gatsby-source-prismic`,
      options: {
        repositoryName: `titirangimedicalcentre`,
        accessToken: `${process.env.API_KEY}`,
        linkResolver: require('./src/utilities/linkResolver').linkResolver,
        schemas: {
          homepage: require("./custom_types/homepage.json"),
          about: require("./custom_types/about.json"),
        },
      },
    },

I am however, receiving the follow warning:

warn ./src/pages/index.js
Attempted import error: '../utilities/CustomLink' does not contain a default
export (imported as 'CustomLink').

Would this be the issue? Do I need to add export default CustomLink to the CustomLink component? The current CustomLink component looks like this:

import React from 'react'
import { Link } from 'gatsby'
import { linkResolver } from './linkResolver'

export const CustomLink = (type, element, content, children, index) => {
  if (element.data.link_type === 'Document') {
    <Link to={linkResolver(element.data)} key={element.data.id}>
      {content}
    </Link>
  }

  if (element.data.link_type === 'Web') {
    <a id={element.data.id} href={element.data.url}>
      {content}
    </a>
  }
  return null
}

How are you importing customLink in your file where you are rendering the Rich Text? Can you paste that code here?

Hi Priyanka,

The specific code for importing the CustomLink is:
import CustomLink from "../utilities/CustomLink"

And here is the context that the CustomLink and RichText components are in:

import * as React from "react"
import { GatsbyImage } from "gatsby-plugin-image"
import { graphql } from "gatsby"
import Layout from "../components/Layout"
import { RichText } from 'prismic-reactjs'
import htmlSerializer from "../utilities/htmlSerializer"
import CustomLink from "../utilities/CustomLink"

function IndexPage({ data }) {
  const doc = data.prismicHomepage.data

  return (
    <Layout title="">
      <div className="wrapper max-w-screen-xl mx-auto p-4 lg:p-8">

        <section className="border-r border-l border-black pl-1/24 pr-1/24 mb-8">
          <div className="py-8 lg:flex">
            <p className="font-display text-4xl md:text-6xl leading-snug md:leading-normal lg:w-8/12 lg:border-r lg:border-black lg:pr-1/24 mb-8">{doc.headline.text}</p>
            <div className="lg:w-4/12 lg:px-1/24 lg:pt-8">
              <RichText htmlSerializer={htmlSerializer} serializeHyperlink={CustomLink} render={doc.lede.raw} />
            </div>
          </div>
        </section>
        //...
    </Layout>
    )
  }

export default IndexPage

in your code import should be:

export const CustomLink = () => {}
import {CustomLink} from '.../utilities/CustomLink' 

Find more details in this documentation:

I hope it solves your issue.

Thanks,
Priyanka

Thanks Priyanka

Can I get some clarification on the following code:

I assume that this is the format my CustomLink component should follow. Is that correct? At the moment my CustomLink looks like this:

// CustomLink.js file

import React from 'react'
import { Link } from 'gatsby'
import { linkResolver } from './linkResolver'

export const CustomLink = (type, element, content, children, index) => {
  if (element.data.link_type === 'Document') {
    <Link to={linkResolver(element.data)} key={element.data.id}>
      {content}
    </Link>
  }

  if (element.data.link_type === 'Web') {
    <a id={element.data.id} href={element.data.url}>
      {content}
    </a>
  }
  return null
}

I have also updated the import to look like this:

import * as React from "react"
import { GatsbyImage } from "gatsby-plugin-image"
import { graphql } from "gatsby"
import Layout from "../components/Layout"
import { RichText } from 'prismic-reactjs'
import htmlSerializer from "../utilities/htmlSerializer"
import { CustomLink } from "../utilities/CustomLink"

function IndexPage({ data }) {
  const doc = data.prismicHomepage.data

  return (
    <Layout title="">
      <div className="wrapper max-w-screen-xl mx-auto p-4 lg:p-8">

        <section className="border-r border-l border-black pl-1/24 pr-1/24 mb-8">
          <div className="py-8 lg:flex">
            <p className="font-display text-4xl md:text-6xl leading-snug md:leading-normal lg:w-8/12 lg:border-r lg:border-black lg:pr-1/24 mb-8">{doc.headline.text}</p>
            <div className="lg:w-4/12 lg:px-1/24 lg:pt-8">
              <RichText htmlSerializer={htmlSerializer} serializeHyperlink={CustomLink} render={doc.lede.raw} />
            </div>
          </div>
        </section>
        //....
      )
  }

Unfortunately I am still getting the following error:

warn ./src/pages/about.js
Attempted import error: '../utilities/CustomLink' does not contain a default
export (imported as 'CustomLink').

As further reference, this is the code in my linkResolver component:

// linkResolver.js file

exports.linkResolver = (doc) => {
  if (doc.type === 'about') {
    return `/${doc.uid}`
  }

  return '/'
}

Hey @hon.boey, thanks for sharing all of these details with us. Are you still having this issue?

Your setup seems to be just fine, and importing the helper like that import { CustomLink } from "../utilities/CustomLink" should have made the error go away. Could you inspect the <a> element that renders in your site and check if the href is being added or not?

Hi @Pau and @Priyanka,

Thank you both for jumping on to this problem for me. After a bit more playing around and with your advice I seemed to have resolved the problem. The issue stemmed from a conflict between the htmlSerializer and the CustomLink components.

I have now deleted the CustomLink component and imported the linkResolver function into htmlSerializer. htmlSerializer now looks like this:

import * as React from 'react'
import { Link } from 'gatsby'
import { Elements } from 'prismic-richtext'
import { Link as PrismicLink } from 'prismic-reactjs'
import { linkResolver } from './linkResolver'

// -- HTML Serializer
const htmlSerializer = function (type, element, content, children, key) {
  switch (type) {

    case Elements.paragraph: // Paragraph
      return <p key={key} className="mb-4">{children}</p>

    //...

    case Elements.hyperlink: // Hyperlinks
      const url = PrismicLink.url(element.data, linkResolver)

      if (element.data.link_type === 'Document') {
        return (
          <Link key={key} to={url}>
            {content}
          </Link>
        )
      }

      return (
        <a
          key={key}
          href={url}
          target={element.data.target}
          rel={element.data.target ? 'noopener' : undefined}
          className="link-class"
        >
          {children}
        </a>
      )

    default:
      // Always include a default that returns null
      return null
  }
}

export default htmlSerializer

Thanks again for your help both of you!

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.