Mar 13
Most useful markdown plugins to use with Astro
by Ryan Welch · 4 Min Read
I’ve put together a list of my favourite markdown plugins for Astro that really make my blog shine. After trying out lots of different options, I’ve settled on the ones that work best for me. In this post, I’ll share what these plugins do, why I like them, and how they can help make your markdown pages better too.
The remark-gemoji ↗ plugin lets you conveniently insert emojis using shortcodes in markdown. Instead of manually copying emojis, you can simply type shortcodes like :smile: to show 😄.
For bloggers or writers who often include mathematical expressions or scientific content, using LaTeX syntax in markdown is essential. The plugins remark-math ↗ and rehype-katex ↗ make this easy by converting markdown math into HTML and rendering them in browsers with KaTeX—a fast math typesetting library.
Install and configure these plugins in your Astro setup:
const astroConfig = { // ...other config options markdown: { remarkPlugins: [remarkGemoji, remarkMath], rehypePlugins: [rehypeKatex], }, // ...rest of config};Add this CSS snippet (assuming Tailwind CSS usage):
.katex-html { @apply hidden;}Callouts help highlight tips, important information, or warnings clearly within your content, making it easier for readers to identify key points at a glance.
Example Callout
This is how an informational callout would look.
The remark-block-containers ↗ plugin provides flexible syntax for creating styled content blocks within markdown files.
Setup:
const astroConfig = { markdown: { remarkPlugins: [remarkGemoji, remarkMath, remarkBlockContainers], rehypePlugins: [rehypeKatex], },};.block-default { @apply border border-border rounded-lg px-6 py-4 my-4;}
.block-default p { @apply my-2;}
.block-title { @apply flex items-center gap-2 font-bold uppercase;}
.block-title::before { @apply inline-block h-5 w-5 bg-current content-['']; mask-repeat: no-repeat; mask-size: cover; mask-image: url(/* lucide-pencil base64 encoded svg */);}
.block-default.info { background-color: var(--blue-1);}
.block-default.info .block-title::before { mask-image: url(/* lucide:info base64 encoded svg */);}Adding a “last modified” timestamp helps readers know how current the content is, while displaying estimated reading times informs them of the commitment required.
Use these custom remark plugins to achieve this:
import { execSync } from 'child_process';
export function remarkModifiedTime() { return function (tree, file) { const filepath = file.history[0]; const result = execSync(`git log -1 --pretty="format:%cI" "${filepath}"`); file.data.astro.frontmatter.lastModified = result.toString(); };}This uses git to find the last commit with a change to the file and then add a new field in the frontmatter of the file. You can then use this field in your Astro template.
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); data.astro.frontmatter.minutesRead = Math.round(readingTime.minutes); };}This plugin uses the reading-time ↗ package to estimate the reading time. There are some config options the library supports such as specifying the average words-per-minute of a reader. Finally, to use the plugins, import and add them to the list of remark plugins in your Astro config.
Astro provides built-in syntax highlighting, but Expressive Code ↗ takes it further by adding window decorations, copy buttons, line highlighting, and code titles. These are great quality of life features which help with readability and if you are sharing snippets.
When managing extensive code snippets, remark-code-import ↗ allows you to import code directly from external files. This keeps markdown files clean, organized, and easier to maintain.
The rehype-figure ↗ plugin automatically wraps markdown images in HTML <figure> tags, using alt text as captions. This improves the semantics and accessibility of your images, making content more meaningful and structured.
To handle external links, use rehype-external-links ↗. It automatically sets attributes like target="_blank" and rel="noopener noreferrer" to external links, enhancing security and user experience.
For articles referencing external sources, rehype-citation ↗ simplifies citation management. It supports various bibliography file formats and then generates a references section at the end of the blog post using any citations from the text and the bibliography provided.
To use it, simply add some additional frontmatter fields to your blog post:
bibliography: ./references-in-bibjson-format.jsonlang: en-UScsl: apa---An example of a citation [@example].There is one issue with the plugin, in that it always looks for bibliography files from root directory, in order to support bibliography paths relative to the markdown file we can use a custom plugin as a wrapper:
const rehypeCitationRelative = (options) => async (tree, file) => { await rehypeCitation({ path: path.dirname(file.history[file.history.length - 1]), ...options, })(tree, file);};These are the plugins I currently use on my blog and support all the features I need so far! Let me know if you have any suggestions or come accross some cool plugins.