MDX components & callouts: Markdown with superpowers
Use Astro components inside Markdown — the bundled <Callout>, JS expressions, slots, and a cookbook for building your own MDX-friendly components.
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 — the build
picks them up via **/*.{md,mdx}.
The theme ships a small, accessible Callout component you can import
in any MDX post:
---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 — they share daisyUI’s semantic colour tokens, so they stay readable in both themes.
MDX evaluates { ... } as JavaScript at build time. Today is Sun Aug 23 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 — _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:
---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:
| Feature | Status |
|---|---|
| TOC | ✓ |
| Code highlight | ✓ |
| Pagefind | ✓ |
| Giscus | ✓ |
This post sets comments: true to demonstrate that flag. To turn
comments off on a single post, set comments: false instead — see the
frontmatter reference and the
Giscus post for the full picture.
Comments
Comments need configuration
Giscus is enabled but not yet configured. Add the repository details below to start collecting comments.
- Visit
giscus.appand select your public GitHub repository (Discussions must be enabled). - Copy the generated
data-repo-id,data-categoryanddata-category-idvalues. - Set the
PUBLIC_GISCUS_ENABLED,PUBLIC_GISCUS_REPO,PUBLIC_GISCUS_REPO_ID,PUBLIC_GISCUS_CATEGORYandPUBLIC_GISCUS_CATEGORY_IDenv vars in your.envfile. - Rebuild the site — this notice will be replaced by the live comments thread.