javascripthtmlcontent-management-systemstrapirich-text-editor

How to create a table of contents from Strapi rich text field


I've searched everywhere for this but I could only find one article about it which was pretty vague.

So I'm rendering the rich text content using the BlocksRenderer component from Strapi itself. Is it possible to create a table of contents from the data gotten from strapi rich text?

This is my Blog component:

import { BlocksRenderer, type BlocksContent} from "@strapi/blocks-react-renderer";

const Blog = () => {

  const { data } = useGetBlogsByIdQuery(slug);

  const content: BlocksContent = data ? .data ? .attributes ? .content;

  return ( 
    <BlocksRenderer content = {content} />
  )
}

This is how the blog post is rendered. If I can map out the headings of each section of the content below the 'on this page' text

This is what the content data looks like

I would appreciate any tips


Solution

  • Just finding out the solution for the same and came across this approach which somehow worked for me.

    heading: ({ children, level }) => {
                    const idString = children
                      .map((child) => child.props.text)
                      .join("-");
                    const id = String(idString)
                      .toLowerCase()
                      .replace(/<\/?[^>]+(>|$)/g, "")
                      .trim()
                      .replace(/\s+/g, "-")
                      .replace(/[^\w-]+/g, "");
    
                    switch (level) {
                      case 1:
                        return (
                          <h1 variant="h1" id={id}>
                            {children}
                          </h1>
                        );
                      case 2:
                        return (
                          <h2 variant="h2" id={id}>
                            {children}
                          </h2>
                        );
                      case 3:
                        return (
                          <h3 variant="h3" id={id}>
                            {children}
                          </h3>
                        );
                      case 4:
                        return (
                          <h4 variant="h4" id={id}>
                            {children}
                          </h4>
                        );
                      case 5:
                        return (
                          <h5 variant="h5" id={id}>
                            {children}
                          </h5>
                        );
                      case 6:
                        return (
                          <h6 variant="h6" id={id}>
                            {children}
                          </h6>
                        );
                      default:
                        return <p variant="p">{children}</p>;
                    }
                  },

       <aside className="hidden lg:block md:w-1/4">
              <div className="sticky top-10 h-screen">
                <h3 className="text-lg my-2">Table of Content</h3>
                <ul className="list-none my-4">
                  {tableOfContents.map((heading) => (
                    <li className="my-2" key={heading.id}>
                      <a
                        href={`#${heading.id}`}
                        className={
                          activeHeading === heading.id
                            ? "text-blue-700"
                            : "text-gray-600"
                        }
                      >
                        {heading.text}
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
            </aside>