provides excellent support for .mdx
files thanks to xdm, allowing you to use Vue components inside markdown, and use markdown components in Vue.
MDX is a format that combines JSX and Markdown, allowing you to embed components in markdown, and use markdown content inside component slots.
---
date: 2020-10-14
---
# Markdown 📖
<Iles/> provides excellent support for `.mdx` files thanks to <kbd>xdm</kbd>,
allowing you to use Vue components inside markdown, and use markdown components
in Vue.
exposes frontmatter properties so that they can be referenced directly in MDX.
---
title: Both of these
description: Will be available as variables in the component.
---
<Tip title={ title }>
{ description }
</Tip>
If you need all properties, you can use the frontmatter
object.
<Summary { ...frontmatter }/>
The filename
and the page href
can be accessed through meta
.
<SuggestChangesLink filename={ meta.filename }/>
extends XDM enabling you to use Vue components in MDX files.
HMR is fully supported, and components can be used without importing them.
Components can receive markdown content using slots:
<Tip title="Markdown in Slots">
This is a _markdown-based_ comment. **Great!**
</Tip>
Markdown in SlotsThis is a markdown-based comment. Great!
The syntax of MDX is different from Vue templates when it comes to binding dynamic values.
Instead of :title="example"
, you would do title={example}
:
export const example = 'Variables in Markdown'
<Tip title={example}>
You can access the document's `frontmatter`, and `meta` info injected by <Iles/>.
And use expressions, such as { meta.lastUpdated.toLocaleDateString('en-US') }.
</Tip>
Variables in MarkdownYou can access the document's
frontmatter
, andmeta
info injected by .And use expressions, such as 12/28/2021.
Markdown files can be used as Vue components, and they will be automatically imported if they are placed in the components dir.
<script setup>
import Acknowledgements from '~/components/Acknowledgements.mdx' // not needed
</script>
<template>
<Acknowledgements/>
</template>
They can also be used in MDX files as components, which is the easiest way to reuse footers or sections that are repeated across documents.
import Acknowledgements from '~/components/Acknowledgements.mdx' // not needed
And _without_ further ado:
<Acknowledgements/>
When importing an MDX component from Vue, you can render its content using <component>
, and access frontmatter
and meta
as properties in the module:
<script setup lang="ts">
import doc from '~/pages/introduction.mdx'
</script>
<template>
<h1>
<a :href="doc.href">{{ doc.title }}</a>
</h1>
<p>{{ doc.frontmatter.description }}</p>
<component :is="doc"/>
<span>Last Updated: {{ formatDate(doc.meta.lastUpdated) }}</span>>
</template>
You can use any components from src/components or those globally registered in Vue without manually importing them in MDX.
If you would like to replace built-in tags such as img
and a
with
custom components, or provide other components, there are two main options.
Use the mdxComponents option to override elements globally in all MDX documents.
import ResponsiveImage from '~/components/ResponsiveImage.vue'
export default defineApp({
mdxComponents: {
img: ResponsiveImage,
},
})
Recommended ✨Easy to setup, and provides consistency in how documents are rendered across the site.
If you need more control, you can use the components
prop in MDX components.
<script setup>
import Introduction from '~/pages/introduction.mdx'
import Footer from '~/components/SpecialFooter.vue'
const components = { Footer }
</script>
<template>
<h1>{{ Introduction.title }}</h1>
<Introduction :components="components"/>
</template>
Use provideMDXComponents
to override elements and components in all nested components. For example, to override components in all pages that use a specific layout:
<script setup>
import { provideMDXComponents } from 'iles'
import Footer from '~/components/PostFooter.vue'
provideMDXComponents({ Footer })
</script>
...
If you need to provide several slots to a component in MDX, you can use v-slots
:
export const titleWithMarkdown = <span>But better keep it <b>simple</b></span>
<Tip warn v-slots={{ title: () => titleWithMarkdown }}>
The syntax is confusing, and you can often achieve the same using props.
</Tip>
But better keep it simpleThe syntax is confusing, and you can often achieve the same using props.