コンテンツにスキップ
まだあたたかい

MDX components & callouts: Markdown with superpowers

Use Astro components inside Markdown  Ethe bundled <Callout>, JS expressions, slots, and a cookbook for building your own MDX-friendly components.

Tutorials 2 分で読めます

When the lines between data and presentation blur, MDX is your friend. You can mix JSX-flavoured components inside Markdown without leaving the authoring flow.

This post is itself an .mdx file. Open src/content/posts/en/mdx-components-and-callouts.mdx to see exactly how the demos below are written.

Use .md when…Use .mdx when…
You only need standard Markdown.You want to import an Astro component.
You want the file to stay portable.You need JS expressions like {new Date()}.
You write a lot of {} literally.You want to compose layout-aware widgets.

Both formats live side-by-side in the same posts/ folder  Ethe build picks them up via **/*.{md,mdx}.

The theme ships a small, accessible Callout component you can import in any MDX post:

src/content/posts/en/example.mdx
---
title: Example
---
import Callout from '../../components/Callout.astro';
<Callout type="info" title="Heads up">
This is an info callout.
</Callout>

It supports four semantic variants  Ethey share daisyUI’s semantic colour tokens, so they stay readable in both themes.

MDX evaluates { ... } as JavaScript at build time. Today is Sat May 09 2026 according to the build server, and 2 + 2 is 4.

Variables defined at the top of the file are also in scope:

export const release = 'v6.0.0';
The latest release is **{release}**.

You are not limited to Callout. Any Astro component can be imported with a relative path. From a post at src/content/posts/en/foo.mdx, the path to a component is ../../components/Foo.astro:

import Panel from '../../components/Panel.astro';
<Panel>
<p>Embedded Panel content here.</p>
</Panel>

Astro components inside MDX accept default slots. Anything between the opening and closing tag is passed as <slot />:

<Callout type="success">
**Anything** can go in here  E_Markdown_, [links](/), even nested components.
</Callout>

Named slots work too if your component declares them:

<MyWidget>
<Fragment slot="header">A heading</Fragment>
Body content goes in the default slot.
</MyWidget>

Want a <Tip> shorthand? Drop a tiny wrapper into src/components/Tip.astro:

src/components/Tip.astro
---
import Callout from './Callout.astro';
---
<Callout type="info" title="Tip">
<slot />
</Callout>

…then use it from any MDX file:

import Tip from '../../components/Tip.astro';
<Tip>Restart `bun run dev` after editing `astro.config.mjs`.</Tip>

Inside MDX, GFM tables, footnotes, and task lists keep working unchanged:

FeatureStatus
TOC✁E
Code highlight✁E
Pagefind✁E
Giscus✁E

This post sets comments: true to demonstrate that flag. To turn comments off on a single post, set comments: false instead  Esee the frontmatter reference and the Giscus post for the full picture.