1.3.0 • Published 10 months ago

react-table-of-content v1.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
10 months ago

React table of content

Provides hooks and utility functions to create a custom and reusable autogenerated table of content for a React project, works really well with markdown content as well.

NPM Downloads GitHub License NPM Version

Table of Contents

Features

  • Generates a table of content based on the headings in a React component.
  • Supports custom selectors for headings.
  • Supports custom dependencies to watch for changes.
  • Provides utility functions to add IDs to heading tags in HTML.
  • Provides utility functions to convert strings to dash case.
  • Provides utility functions to convert links in HTML to external links (open in new tab).
  • Lightweight and easy to use.
  • No dependencies.

Installation

npm install react-table-of-content

Usage

import React from "react";
import { useTableOfContent } from "react-table-of-content";

export const TableOfContent: React.FC<{}> = () => {
  const { headingLinks, contentIsActive } = useTableOfContent();

  //   return (
  //     <>JSX</>
  //   )
};

Example implementation

You can create a reusable component that generates a table of content for your page using the hook. See the example below.

import React from "react";
import { useTableOfContent } from "react-table-of-content";

export const TableOfContent: React.FC<{}> = () => {
  const { headingLinks, contentIsActive } = useTableOfContent({
    selectors: "article h1, article h2, article h3",
  });

  if (!headingLinks || headingLinks.length < 1) return null;

  return (
    <div>
      <h4 id="on-this-page">ON THIS PAGE</h4>
      <ul className="mt-4 space-y-2">
        {headingLinks.map((link) => {
          const isActive = contentIsActive(link.id);

          return (
            <li key={link.id}>
              <a
                className={`${
                  isActive ? "text-gray-800 font-semibold" : "text-gray-500"
                }
                ${["h3", "h4"].includes(link.tagName.toLowerCase()) && "pl-2"}
                ${["h5", "h6"].includes(link.tagName.toLowerCase()) && "pl-4"}
                hover:text-gray-700 transition-colors duration-200
                `}
                href={`#${link.id}`}
              >
                {link.title}
              </a>
            </li>
          );
        })}
      </ul>
    </div>
  );
};

You can then use the component in your page like so:

import React from "react";
import { TableOfContent } from "./TableOfContent";

export const App: React.FC = () => {
  return (
    <div className="flex">
      <div className="p-10 w-64">
        <div className="sticky top-8">
          <div className="mb-2">
            <img className="w-8 h-8" src="/favicon.png" alt="logo" />
          </div>
          <TableOfContent />
        </div>
      </div>
      <div className="flex-1">
        <Article />
      </div>
    </div>
  );
};

Below is an example of an article component that has headings.

import React from "react";

const Article = () => {
  const headingTags = ["h1", "h2", "h3", "h4", "h5", "h6"];
  const dummyText =
    "Lorem ipsum dolor sit amet consectetur adipisicing elit. Laborum vero accusamus alias cumque numquam atque eius ullam nobis at! Necessitatibus, corporis earum? Quidem, corporis blanditiis sapiente veritatis saepe debitis expedita!.";
  return (
    <article>
      <div className="container max-w-screen-xl">
        {headingTags.map((tag, index) => {
          const headingElement = createElement(
            tag,
            { key: index, id: `${tag}-heading` },
            `${tag.toUpperCase()} heading`
          );
          return (
            <section key={index}>
              {headingElement}
              {/* Returns something like this: <h1 id={`${tag}-heading`}>{tag.toUpperCase()} heading</h1> */}
              <p>{dummyText}</p>
            </section>
          );
        })}
      </div>
    </article>
  );
};

API

Hooks

useTableOfContent

The useTableOfContent hook generates a table of content for a React component based on the headings in the component.

Arguments
NameTypeRequiredDefaultDescription
selectorsstringOptional"h1, h2, h3"A string of comma-separated selectors to use to generate the table of content.
depsunknownOptionalundefinedAn item to be used within the dependency array to watch for changes.
Return value

An object with the following properties:

NameTypeDescription
headingLinksarrayIt contains an array of objects that have the following properties:id (string): The ID of the heading, title (string): The text content of the heading, tagName (string): The tag name of the heading.
contentIsActivefunctionA function that takes an ID of the headingLink and returns a boolean indicating whether the content with that ID is active.

Utility functions

The package also exports utility functions that can be used to generate the table of content.

addIdToHeadingTags

The addIdToHeadingTags function adds an ID to each heading tag in a string of HTML.

Arguments

Accepts 1 argument of type string containing the HTML to add IDs to heading tags.

Return value

A string of HTML with IDs added to the heading tags.

Usage and example
import { addIdToHeadingTags } from "react-table-of-content";

const html = `
  <h1>Heading 1</h1>
  <p>Content 1</p>
  <h2>Heading 2</h2>
  <p>Content 2</p>
`;

const newHtml = addIdToHeadingTags(html);

console.log(newHtml);

// Output:
// <h1 id="heading-1">Heading 1</h1>
// <p>Content 1</p>
// <h2 id="heading-2">Heading 2</h2>
// <p>Content 2</p>

dashCase

It's a function that converts a string to dash case.

Arguments

Accepts 1 argument of type string to be transformed to a dash cased format.

Return value

A string in dash case.

Usage and example
import { dashCase } from "react-table-of-content";

const str = "This is a string";

const newStr = dashCase(str);

console.log(newStr);

// Output:
// this-is-a-string

makeLinksExternal

It's a function that converts all links in a string of HTML to external links.

Arguments

Accepts 1 argument of type string containing the HTML to convert links to external links.

Return value

A string of HTML with links converted to external links.

Usage and example
import { makeLinksExternal } from "react-table-of-content";

const html = `
  <a href="/about">About</a>
  <a href="/contact">Contact</a>
`;

const newHtml = makeLinksExternal(html);

console.log(newHtml);

// Output:
// <a href="/about" target="_blank" rel="noopener noreferrer">About</a>
// <a href="/contact" target="_blank" rel="noopener noreferrer">Contact</a>

readTime

It's a function that calculates the read time of a string of text.

Arguments

Accepts 1 argument of type string containing the text to calculate the read time.

Return value

An object with minutes property of type number in minutes and a readTime property describing the number in words e.g. "1 min read".

Usage and example
import { readTime } from "react-table-of-content";

const text =
  "This is a string of text that will be used to calculate the read time.";

const time = readTime(text);

console.log(time);

// Output:

// { minutes: 1, readTime: "1 min read" }

Testing

Unit and integration tests are written using Jest and React Testing Library. To run the tests, use the command below:

npm run test

You can mock the package in your tests like so:

jest.mock("react-table-of-content", () => ({
  addIdToHeadingTags: jest.fn((content) => content),
  useTableOfContent: jest.fn(() => ({
    headingLinks: [
      {
        id: "id",
        title: "title",
        tagName: "h1",
      },
    ],
    contentIsActive: jest.fn(() => true),
  })),
  makeLinksExternal: jest.fn((content) => content),
}));

License

MIT

Author

Precious OSSAI

Developer Website

1.3.0

10 months ago

1.2.0

10 months ago

1.1.0

10 months ago

1.0.0

10 months ago