Skip to content

RFC: placeholder components after title, after content, after pagination, etc. #5251

@Josh-Cena

Description

@Josh-Cena

🚀 Feature

Update on how the API would like after some discussion:

The DocItem component right now is something like:

<div>
  <DocVersionBanner />
  <div>
    <article>
      <span>
        Version: {versionMetadata.label}
      </span>
      <TOCCollapsible />
      <div>
        <MainHeading>{title}</MainHeading>
        <DocContent />
      </div>

      <footer>
        <div>
          <EditThisPage />
        </div>
        <div>
          <LastUpdated />
        </div>
      </footer>
    </article>
    <DocPaginator />
  </div>
</div>

We can have additional placeholder components at some "anchor points", meant to be swizzled:

  <div>
    <DocVersionBanner />
+   <AfterVersionBanner doc={DocContent} />
    <div>
      <article>
        <span>
          Version: {versionMetadata.label}
        </span>
+       <AfterVersionBadge doc={DocContent} />
        <TOCCollapsible />
        <div>
          <MainHeading>{title}</MainHeading>
+         <AfterHeading doc={DocContent} />
          <DocContent />
+         <AfterMainContent doc={DocContent} />
        </div>

        <footer>
          <div>
            <EditThisPage />
+           <AfterEdit doc={DocContent} />
          </div>
          <div>
            <LastUpdated />
+           <AfterLastUpdated doc={DocContent} />
          </div>
        </footer>
      </article>
      <DocPaginator />
+     <AfterPaginator doc={DocContent} />
    </div>
  </div>

These anchor components are initially empty:

export default function AfterHeading({doc}) {
  return null;
}

But users can swizzle these elements and add custom logic. All the doc's data is provided through props, including front matter, metadata, title, content, etc., from which the user can pick and display.

export default function AfterHeading({doc}) {
  const {frontMatter} = doc;
  const {date, link} = frontMatter;
  return (
    <div className="alert alert--info margin-bottom--md" role="contentinfo">
      First published on <b>{date.toLocaleDateString()}</b>.
      <Link to={link}>Source link</Link>
    </div>
  );
}

Some use-cases:

  • A metadata list displaying author, source link, publication date, etc., after the heading;
  • GitHub status badges after the heading;
  • A custom feedback widget at the bottom, just like the discussion in [v2] Integrated Feedback Widget #4808;
  • "Related links" at the bottom...

Benefits:

  • Reduced code duplication: the same component doesn't have to be injected for every Markdown file, but is handled during doc loading;
  • Reduced user burden: users don't have to swizzle the entire DocItem just to add one custom component, resulting in additional burden to keep it up-to-date in the future;
  • Easy extensibility: this conforms to Docusaurus's goal of making themes easily extended, since the user is only interacting with a very lightweight API;
  • Not opinionated: all the logic is user-provided, and the Docusaurus doesn't provide any implementation details. This single generic API can satisfy a range of different needs.

Original proposal

Users may want a banner at the beginning of every documentation page containing some metadata like:

  • Original source link, if this is an imported content;
  • Author & Publish date (which may be different from the git info);
  • Tags / thumbnail image.

Have you read the Contributing Guidelines on issues?

Yes

Has this been requested on Canny?

No

Motivation

Additional front matter should not be eaten up by the renderer but should find a way to be displayed. This frees the user from copy & pasting the same component (or importing them) to every page.

API Design

  1. We will provide a metadataBanner option in plugin-docs (default is false). When set to true, a @theme/docMetadataBanner component will be injected at the beginning of every file—similar to the version banner. The metadataBanner option will also accept a string path to a user-defined component, or the user can choose to swizzle @theme/docMetadataBanner instead.
  2. The @theme/docMetadataBanner component will receive content as props (typing similar to DocItem.Props) from which metadata, frontMatter, etc., can be extracted.
  3. The front matter that's already been picked up will be pruned, like:
const {title, sidebar_label, id, /* ..., */ ...customFrontMatter} = frontMatter;
  1. The default rendering method can be an info box:
<div className="alert alert--info margin-bottom--md" role="contentinfo">
  <div className="margin-top--md">
    <ul>
      {
        Object.keys(customFrontMatter).map((key, i) => <li key={i}>{key}: {JSON.stringify(customFrontMatter[key])}</li>)
      }
    </ul>
  </div>
</div>

But users can easily customize it to show something they want, since they also know better of what custom front matter they have.

Have you tried building it?

Did some preliminary work to demonstrate what it would look like:

image

(Note: I used JSON.stringify() to force all front matter to strings. In practice, the date may be rendered with date.toLocaleDateString().)

Metadata

Metadata

Assignees

No one assigned

    Labels

    closed: wontfixA fix will bring significant overhead, or is out of scope (for feature requests)featureThis is not a bug or issue with Docusausus, per se. It is a feature request for the future.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions