Adding Reading Time to Astro Content Collections

4 min read

Here is the way that I added reading time to every Astro blog post.

FIRST The Most Important Step

Count. every. word. with. your. eyes.

Before I get started, I first do some eye exercises.

Before getting down to counting, I like to close my eyes for 2 minutes and picture every letter in the alphabet, forwards and backwards. Then after counting to 10, I repeat the process, but this time I start backwards to forwards.

Once I feel mentally prepared. I open the .mdx file and read through, skipping every other line. Once I’m done this first pass, I then start again, this time reading only the lines that I skipped.

Now that I’ve given my eyes a good warm up… we just copy pasta:


The Javscript to add Reading Time

I added the js in a utils file in my utils folder that I use for… utility functions.

utils.js
export function readingTime(s) {
  const wpm = 200;
  const n = s
    .replace(/[^\w\s]/gi, "")
    .replaceAll("\r", "")
    .replaceAll("\n", "")
    .split(" ").length;

  return Math.ceil(n / wpm);
}

JS Explainer

The calculation happens before Astro renders the mdx to html.

According to scholarwithin.com the average reading speed for an adult is 238. I then just checked on stackoverflow, who told me to use 200.

.replace(/[^\w\s]/gi, " ") should remove any white space and character that isn’t a letter or number and the next 2 replaces any \r or \n that is added in the text. Finally .split(" ").length; parses the string into an array to get the length.

The replace regex could probably be better, but my regex kung-fu is not strong.


Using the Script

Import the script at the top of the file that reads the content collection.

[…slug].astro
import { readingTime } from "@utils/utils";

const post = await Astro.props;
const timeToRead = readingTime(post.body);

I passed it into my PostHeader component:

<PostHeader {...post.data} timeToRead={timeToRead} />

Which has a simple:

PostHeader.astro
---
const { timeToRead } = Astro.props;
---

<div class='mt-2'>{timeToRead} min. read</div>

Tada.

[edit] Also, this is post #10 - woohoo

[edit: 2024-02-14] Part of my Astro repo: AstroJS utils function