Skip to content

astro

Add reading time

Astro

Add reading time

Add reading time

Create a remark plugin which adds a reading time property to the frontmatter of your Markdown or MDX files. Use this property to display the reading time for each page.

Recipe

1. Install the following packages: - [`reading-time`](https://www.npmjs.com/package/reading-time) to calculate minutes read - [`mdast-util-to-string`](https://www.npmjs.com/package/mdast-util-to-string) to extract all text from your markdown - [`@astrojs/markdown-remark`](https://www.npmjs.com/package/@astrojs/markdown-remark) to use [the `unified()` processor](/en/guides/markdown-content/#using-remark-and-rehype-plugins):
<PackageManagerTabs>
  <Fragment slot="npm">
  ```shell
npm install reading-time mdast-util-to-string @astrojs/markdown-remark
  ```
  </Fragment>
  <Fragment slot="pnpm">
  ```shell
pnpm add reading-time mdast-util-to-string @astrojs/markdown-remark
  ```
  </Fragment>
  <Fragment slot="yarn">
  ```shell
yarn add reading-time mdast-util-to-string @astrojs/markdown-remark
  ```
  </Fragment>
</PackageManagerTabs>
  1. Create a remark plugin.

    This plugin uses the mdast-util-to-string package to get the Markdown file's text. This text is then passed to the reading-time package to calculate the reading time in minutes.

    import getReadingTime from 'reading-time';
    import { toString } from 'mdast-util-to-string';
    
    export function remarkReadingTime() {
      return function (tree, { data }) {
        const textOnPage = toString(tree);
        const readingTime = getReadingTime(textOnPage);
        // readingTime.text will give us minutes read as a friendly string,
        // i.e. "3 min read"
        data.astro.frontmatter.minutesRead = readingTime.text;
      };
    }
  2. Add the plugin to your config:

    import { unified } from '@astrojs/markdown-remark';
    import { defineConfig } from 'astro/config';
    import { remarkReadingTime } from './remark-reading-time.mjs';
    
    export default defineConfig({
      markdown: {
        processor: unified({
          remarkPlugins: [remarkReadingTime],
        }),
      },
    });

    Now all Markdown documents will have a calculated minutesRead property in their frontmatter.

  3. Display Reading Time

    If your blog posts are stored in a content collection, access the remarkPluginFrontmatter from the render(entry) function. Then, render minutesRead in your template wherever you would like it to appear.

    ---
    import { getCollection, render } from 'astro:content';
    
    export async function getStaticPaths() {
      const blog = await getCollection('blog');
      return blog.map(entry => ({
        params: { slug: entry.id },
        props: { entry },
      }));
    }
    
    const { entry } = Astro.props;
    const { Content, remarkPluginFrontmatter } = await render(entry);
    ---
    
    <html>
      <head>...</head>
      <body>
        ...
        <p>{remarkPluginFrontmatter.minutesRead}</p>
        ...
      </body>
    </html>

    If you're using a Markdown layout, use the minutesRead frontmatter property from Astro.props in your layout template.

    ---
    const { minutesRead } = Astro.props.frontmatter;
    ---
    
    <html>
      <head>...</head>
      <body>
        <p>{minutesRead}</p>
        <slot />
      </body>
    </html>