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
<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>
Create a remark plugin.
This plugin uses the
mdast-util-to-stringpackage to get the Markdown file's text. This text is then passed to thereading-timepackage 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; }; }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
minutesReadproperty in their frontmatter.Display Reading Time
If your blog posts are stored in a content collection, access the
remarkPluginFrontmatterfrom therender(entry)function. Then, renderminutesReadin 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
minutesReadfrontmatter property fromAstro.propsin your layout template.--- const { minutesRead } = Astro.props.frontmatter; --- <html> <head>...</head> <body> <p>{minutesRead}</p> <slot /> </body> </html>