Simplify Svelte Site Content with MDsveX

15 Aug 2025

blog header

Let’s face it, when it comes to writing content for the web, whether it’s a blog, technical doc or any other text-based document, using HTML is a pain. The syntax is tedious and frankly just is not meant for writing large text articles.

Wouldn’t it be nice to write content for our website in a language better suited for text documents? Personally I adore Markdown, it has simple, readable syntax while still being feature rich. Being able to write content for our Svelte site with markdown would greatly improve our quality of life.

Introducing MDsveX! Not only can we write and render content using markdown, but we can also integrate seamlessly with Svelte to render out components and other Svelte code in the same document.

Note

Check out the tutorial site for a live demonstration of this guide in action. You can also view the its source code on GitHub.

Setup

SvelteKit apps can be bootstrapped to include MDsveX out of the box using the SvelteKit CLI. If you haven’t done this, setup is still simple. Install MDsveX — npm install --save-dev mdsvex — then add MDsveX as a preprocessor step, specifying .svx and/or .md as valid file extensions. This can be done through the svelte.config.cjs:

import { mdsvex } from 'mdsvex';

const config = {
	preprocess: [
		mdsvex({
			extensions: ['.md', '.svx']
		})
	],
	extensions: ['.svelte', '.svx', '.md']
};

export default config;

By adding MDsveX to the config, files with the specified extensions, in this case .svx and .md will have their contents transformed to a proper Sveltified output. The Svelte compiler can then handle them as they would any other .svelte file.

Rendering Content

With MDsveX setup in our Svelte app the first step is to write some content for our website. Create a valid MDsveX file. We can keep it simple for now and write a markdown file:

# My Article Article contents for my Svelte site.

Or go with a .svx file to use both markdown and Svelte in the same file.

<script lang="ts">
	import Component from '$lib/component.svelte';
</script>

# My Article My fancy article with Svelte components.

<Component />

We can now import and use MDsveX files as Svelte components and use them as you would any Svelte component.

<script lang="ts">
	import Article from '$lib/content/article.svx';
</script>

<Article />

Adding Typography

Our MDsveX file content will now be rendered on our website as HTML, however, there will be no styling applied by default, making our article boring and plain. Generally we want to have some beautiful document styling applied to all our text-based web content. The best way to do this is by applying some kind of typography.

There are many ways to apply typography, one way would be to make a custom typography stylesheet and apply it either site wide or to the article itself. Personally, I use a lot of Tailwind CSS, Tailwind provides an official Typography plugin. Simply install and configure the plugin. Then add the prose class to your article. Now all our HTML will have some nice default typography styling applied (feel free to customize).

<script lang="ts">
	import Article from '$lib/content/article.svx';
</script>

<Article class="prose" />

Using Frontmatter

Oftentimes we will want our documents to contain metadata. This could be used to render additional content or to provide related data to be used in document searching or SEO. MDsveX makes this data easy to handle.

Define frontmatter by enclosing a yaml block in --- characters:

--- 
title: My Awesome Article 
author: Fancy Dev 
---

Frontmatter can be used in the document itself by referencing it in brackets.

--- 
title: My Awesome Article 
author: Fancy Dev 
--- 

# {title}

Metadata will also be available when importing your document, by importing the metadata export.

<script lang="ts">
	import Article, { metadata } from '$lib/content/article.svx';
</script>

<div class="prose">
	<Article />
	<hr />
	<p><b>Author:</b> {metadata.author}</p>
</div>

Using Svelte Components

One of the benefits of MDsveX is that we can write Svelte code alongside our markdown. This means that we can use Svelte components in our document just as we would anywhere else in our Svelte app. For instance, this simple counter component can be used in our .svx file in the same way it would anywhere else in our app.

<script>
	let count = 0;

	function increment() {
		count += 1;
	}
</script>

<p>You clicked {count} {count === 1 ? 'time' : 'times'}.</p>
<button on:click={increment}> Click me </button>

Now import and render the counter component in Svelte.

<script lang="ts">
	import Counter from '$lib/components/counter.svelte';
</script>

--- 
title: My Awesome Article 
author: Fancy Dev 
--- 

# {title}

Here is a Svelte component inserted alongside markdown!

<Counter />

Applying Layouts

Most of the time we will want our text content to contain similar components or have consistent formatting. Rather than handling this for every MDsveX document we write, we can instead create some generic layouts and then apply it to all or specific files.

To create a layout, create a Svelte component that has children as a prop as well as any metadata you want to use in the layout. For example we can create a simple Svelte component to act as a layout for an article:

<script lang="ts">
	import { ComponentExample } from '$lib/components'

	import { author, children} = $props()
</script>

<article class="article-style">
	{@render children?.()}
	<hr />
	<p><b>Author:</b> {author}</p>
</article>

<ComponentExample />

The children prop will be the Sveltified MDsveX file content, and the author prop will come from the frontmatter. To start using this layout register it through the MDsveX plugin.

mdsvex({
	layout: {
		article: 'src/lib/layout/article.svelte'
	}
});

The layout can automatically be applied to a MDsveX document by specifying it in the layout frontmatter.

--- 
layout: article 
title: My Awesome Article 
author: Fancy Dev 
---

Now, when we import and use our MDsveX document, it will be automatically inserted into the specified layout component.

Syntax Highlighting

Code blocks are a very common item to include in our content. This creates the need for syntax highlighting. MDsveX adds this functionality by default using Prismjs. However, Prism is an older library and I recommend using Shiki instead. To configure this you can add a custom highlight function to the MDsveX configuration.

import { escapeSvelte, mdsvex } from 'mdsvex';
import { createHighlighter } from 'shiki';

const theme = 'one-dark-pro';
const highlighter = await createHighlighter({
	themes: [theme],
	langs: ['javascript', 'typescript', 'markdown', 'svelte']
});

mdsvex({
	highlight: {
		highlighter: async (code, lang = 'text') => {
			const html = escapeSvelte(
				highlighter.codeToHtml(code, { lang, theme })
			);
			return `{@html `${html}` }`;
		}
	}
});

Rehype and Remark

At its core MDSveX is built on top of the unified ecosystem. This means that useful plugins can be added to allow further customization. You can use remark to customize the transformation of your document’s markdown and rehype to customize the HTML transform.

Remark and rehype plugins can be slotted into the MDSveX configuration.

mdsvex(
	{
		remarkPlugins: [someRemarkPlugin]
		rehypePlugins: [someRehypePlugin]
	}
)
Note

I have had issues using some remark and rehype plugins, it is not a flawless integration. Additionally the maintainers have expressed the desire to move away from unified. Future support for this toolchain in MDsveX is questionable.

Conclusion

We have covered how to setup your Svelte app with MDsveX. Hopefully, I have demonstrated the power of this tool and how to leverage it to make writing content for your website much easier. Obviously there is more work to be done to create an effective content system for your website, but I hope this tutorial has unlocked the potential of MDsveX in your Svelte applications.