Skip to content

Add Reading Time

2 min read

This recipe shows one way to display an estimated reading time for each page in Starlight.

  1. Install the required packages:

    Terminal window
    npm add reading-time mdast-util-to-string unified @types/mdast
  2. Create a remark plugin to calculate reading time.
    Save the file as src/plugins/remark-reading-time.ts:

    src/plugins/remark-reading-time.ts
    import type { Root } from "mdast";
    import { toString as mdToString } from "mdast-util-to-string";
    import getReadingTime from "reading-time";
    import type { Plugin } from "unified";
    interface AstroRemarkData {
    astro: {
    frontmatter: Record<string, unknown>;
    };
    }
    export const remarkReadingTime: Plugin<[], Root> = () => {
    return (tree: Root, file) => {
    const data = file.data as Partial<AstroRemarkData>;
    if (!data.astro) data.astro = { frontmatter: {} };
    if (!data.astro.frontmatter) data.astro.frontmatter = {};
    const textOnPage = mdToString(tree);
    const readingTime = getReadingTime(textOnPage);
    data.astro.frontmatter.minutesRead = readingTime.text; // e.g. "3 min read"
    };
    };
  3. Override Starlight’s PageTitle component to display reading time: Create src/components/PageTitle.astro:

    src/components/PageTitle.astro
    ---
    /*
    * Implement the source code according to Astro Docs:
    * https://github.com/withastro/docs/blob/main/src/components/starlight/PageTitle.astro
    */
    import { render } from "astro:content";
    import { Icon } from "@astrojs/starlight/components";
    const { entry } = Astro.locals.starlightRoute;
    const { data } = Astro.locals.starlightRoute.entry;
    const { remarkPluginFrontmatter } = await render(entry);
    ---
    <div class="wrapper">
    <h1 id="_top">
    <span>{data.title}</span>
    </h1>
    <p class="sl-flex">
    <Icon name="seti:clock" size="1.2em" />
    {remarkPluginFrontmatter.minutesRead}
    </p>
    </div>
    <style>
    .wrapper {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    }
    h1 {
    display: flex;
    flex-wrap: wrap;
    color: var(--sl-color-white);
    font-size: var(--sl-text-h1);
    font-weight: 600;
    line-height: var(--sl-line-height-headings);
    }
    p {
    gap: 0.5rem;
    align-items: center;
    text-decoration: none;
    color: var(--sl-color-gray-3);
    }
    </style>
  4. Add the plugin to your config and tell Starlight to use your custom PageTitle:

    astro.config.mjs
    import { defineConfig } from "astro/config";
    import starlight from "@astrojs/starlight";
    import { remarkReadingTime } from "./src/plugins/remark-reading-time";
    export default defineConfig({
    markdown: {
    remarkPlugins: [remarkReadingTime],
    },
    integrations: [
    starlight({
    components: {
    PageTitle: "./src/components/PageTitle.astro",
    },
    }),
    ],
    });
  1. Add reading time - Astro Docs