Using MDX

This theme comes with the @astrojs/mdx integration installed and configured in your astro.config.mjs config file. MDX allows you to use JSX components directly in your Markdown content.

Why MDX?

MDX is a special flavor of Markdown that supports embedded JavaScript & JSX syntax. This unlocks the ability to mix JavaScript and UI Components into your Markdown content for things like interactive elements, callouts, and dynamic data.


Callout Components

Callouts are great for highlighting important information. Here are the available types:

Pro Tip

Use callouts to draw attention to important information that readers shouldn’t miss.

Note

This is a note callout. It’s useful for additional context or explanations.

Warning

Be careful! This warning callout indicates something that could cause issues.

Critical

This is a danger callout for critical warnings that require immediate attention.

Usage:

import Callout from '../../../components/mdx/Callout.astro';

<Callout type="tip" title="Custom Title">
  Your content here...
</Callout>

Interactive Components

MDX supports React components with client-side interactivity. Use Astro’s client: directives to hydrate components.

Counter Example

This counter is a React component that maintains state:

Clicks:
0

You can customize the initial value and step:

Score:
10

Usage:

import { Counter } from '../../../components/mdx/Counter.tsx';

<Counter client:visible label="Clicks" />
<Counter client:visible initialValue={10} step={5} label="Score" />
Note

The client:visible directive means the component only hydrates when it enters the viewport, improving performance.


Image Components

This theme includes several image components for enhanced UX, accessibility, and SEO.

Figure with Caption

Use Figure for images that need semantic captions:

A scenic mountain landscape with clouds
Beautiful mountain scenery at sunset Photo by Unsplash

Usage:

import Figure from '../../../components/mdx/Figure.astro';
import myImage from '../../../assets/my-image.jpg';

<Figure
  src={myImage}
  alt="Description of the image"
  caption="Caption text shown below"
  credit="Optional credit"
/>

Click the image below to open it in a fullscreen lightbox. Press Escape to close.

Usage:

import { Lightbox } from '../../../components/mdx/Lightbox.tsx';

<Lightbox
  client:visible
  src="/path/to/image.jpg"
  alt="Description"
  caption="Optional caption"
/>

A responsive grid gallery with built-in lightbox navigation. Use Arrow keys to navigate, Escape to close.

Usage:

import { Gallery } from '../../../components/mdx/Gallery.tsx';

<Gallery
  client:visible
  columns={3}  // 2, 3, or 4
  gap="md"     // sm, md, or lg
  images={[
    { src: "/img1.jpg", alt: "Description 1", caption: "Caption 1" },
    { src: "/img2.jpg", alt: "Description 2", caption: "Caption 2" },
  ]}
/>

Before/After Comparison Slider

Drag the slider or use Arrow keys to compare images:

Edited imageAfter
Original imageBefore

Usage:

import { BeforeAfter } from '../../../components/mdx/BeforeAfter.tsx';

<BeforeAfter
  client:visible
  beforeSrc="/before.jpg"
  afterSrc="/after.jpg"
  beforeAlt="Before description"
  afterAlt="After description"
  beforeLabel="Before"
  afterLabel="After"
/>

Blur-up Placeholder

Images load with a blurred placeholder for better perceived performance:

City skyline with blur-up loading effect

Usage:

import BlurImage from '../../../components/mdx/BlurImage.astro';
import myImage from '../../../assets/my-image.jpg';

<BlurImage src={myImage} alt="Description" />
Tip

All interactive image components use client:visible to only hydrate when they enter the viewport, keeping your pages fast!


Video Components

This theme includes two video components: one for embedding YouTube/Vimeo videos and another for self-hosted videos.

VideoEmbed (YouTube/Vimeo)

Embed videos from YouTube or Vimeo with privacy-enhanced mode:

Big Buck Bunny - Blender Foundation

Use hideControls={true} to completely hide the control bar for a cinematic look (click video to play/pause):

Big Buck Bunny - Open Source Animation

Usage:

import { VideoEmbed } from '../../../components/mdx/VideoEmbed.tsx';

<VideoEmbed
  client:visible
  src="https://www.youtube.com/watch?v=VIDEO_ID"
  title="Video title for accessibility"
  aspectRatio="16:9"  // 16:9, 4:3, 1:1, or 9:16
  minimal={true}      // Hide branding, annotations, fullscreen
  hideControls={true} // Hide control bar completely
  autoplay={false}
  muted={false}
  loop={false}
  start={30}  // Start at 30 seconds (YouTube only)
/>
Note

VideoEmbed shows a thumbnail preview and only loads the video player when clicked. It uses privacy-enhanced URLs (youtube-nocookie.com and Vimeo’s DNT mode) to respect visitor privacy.


Self-Hosted Video

For videos hosted on your own server, use the Video component with native HTML5 controls:

Self-hosted video example

Usage:

import Video from '../../../components/mdx/Video.astro';
import posterImage from '../../../assets/video-poster.jpg';

<Video
  src="/videos/my-video.mp4"
  poster={posterImage}
  title="Video caption"
  aspectRatio="16:9"
  autoplay={false}
  muted={false}
  loop={false}
  controls={true}
  preload="metadata"  // none, metadata, or auto
/>

{/* Multiple formats for browser compatibility */}
<Video
  src={["/videos/video.webm", "/videos/video.mp4"]}
  title="Video with format fallbacks"
/>
Tip

For autoplay to work without user interaction, videos must be muted. The Video component handles this automatically.


Inline JavaScript Expressions

MDX allows you to embed JavaScript expressions directly in your content:

  • Current year: 2026
  • Math calculation: 2 + 2 = 4
  • Conditional: Yes!

You can also use variables:

  • Project: OXCOMY
  • Version: 1.0.0

Using Astro Components

You can import and use Astro components in MDX. Here’s a formatted date component:

Today’s date:

A specific date:


Combining Markdown and JSX

One of MDX’s strengths is seamlessly mixing Markdown syntax with JSX:

This is a styled container

You can write regular Markdown inside JSX elements:

  • List items work
  • Italic and bold too
  • Even inline code

Client Directives Reference

When using React/Vue/Svelte components, choose the right hydration strategy:

DirectiveWhen it Hydrates
client:loadImmediately on page load
client:idleWhen the browser is idle
client:visibleWhen component enters viewport
client:mediaWhen media query matches
client:onlySkips server render, client-only

More Resources

Tip

Remember: Components in MDX render as static HTML by default. Add a client:* directive for interactivity!

0 Comments

Loading comments...