Skip to content

Astro and mdx and components in markdown

Posted on:April 1, 2023

I had an old blog written in Jekyll that I started in 2013 but it hadn’t been updated in an embarassingly long time so I decided to start so fresh and so clean clean. Here we are, a new website built with Astro. Unless you’ve been living under a rock (or if you’re not a web dev) you’ve probably heard of it.

One of the coolest things it brings to the table is it’s “Component Islands” architecture, so like think of the various components your app might have: header, navigation, sidebar, footer, etc. Some of these components could be mostly static like your footer but you may also have something like an image carousel component that’s interactive. In astro you can mix and match your UI framework, hypothetically you could have a header written in Svelte, a sidebar written in Vue, and an image carousel written in React. Although I’m not quite sure why anyone in their sane mind would do that. Anyways, the biggest benefit of astro islands is performance, most of your website is converted to fast static html and the javascript is only loaded for the individual components that actually need it.

My favorite, and newish part of Astro is the ability to use mdx files which is like markdown but with jsx, so if I want I can build little components and slap them in my blog post, for example:

or like make this super fun game where the goal is to click the button 10 times:

That’s pretty awesome, right? Astro gives you multiple client directives:

For example, with my Dadjoke component, I set it to client:visible so the javascript doesn’t load until the component reaches the user’s viewport.

<Dadjoke client:visible />

and you’re probably wanting my amazing Dadjoke component, so here you go:

import { useState } from "react";

const Dadjoke = () => {
	const [joke, setJoke] = useState < string > "";

	const generateDadJoke = () => {
		fetch("", {
			headers: {
				Accept: "application/json",
			.then(res => res.json())
			.then(data => setJoke(data.joke));

	return (
			<button className="btn" onClick={generateDadJoke}>
				{joke ? "👴 Generate Another Dad Joke 🤪" : "👴 Generate Dad Joke 👴"}
			{joke && <blockquote>{joke}</blockquote>}

export default Dadjoke;
Edit on Github
More Posts