Custom Components
Replace default HTML elements with custom Svelte components for enhanced functionality.
MDSX allows you to replace default HTML elements like <h1>, <p>, and <a> with your own custom Svelte components.
You might use custom components to:
- Apply consistent brand styling to headings and paragraphs.
- Automatically add
target="_blank"to external links. - Replace standard
<img>tags with an advanced image component that handles lazy loading and placeholders.
How It Works
Custom components are provided through Blueprints.
When you export a component from a blueprint file with a name that matches an HTML tag (e.g., h1, p, a), MDSX automatically uses your component for all corresponding tags in any markdown file that uses that blueprint.
These components are exported from the <script module> block of a blueprint file.
Creating a Custom Component
A custom component is just a standard Svelte component. It receives the original element's content as the children prop, which is a Svelte 5 Snippet.
Here's an example of a custom component for an <h1> element:
<script lang="ts">
import type { Snippet } from 'svelte';
let { children }: { children: Snippet } = $props();
</script>
<h1 class="mb-6 border-b-2 border-gray-200 pb-2 text-4xl font-bold text-gray-900">
{@render children()}
</h1>
Using a Custom Component
To use this component, you export it from a blueprint with the corresponding tag name.
<script lang="ts" context="module">
export { default as h1 } from '$lib/components/h1.svelte';
</script>
<script lang="ts">
import type { Snippet } from 'svelte';
let { children }: { children: Snippet } = $props();
</script>
<article class="prose">
{@render children()}
</article>
Now, whenever a markdown file using this blueprint contains an <h1>, it will be rendered with your h1.svelte component.
Example: Custom Anchor Tag
Let's create a custom <a> component that automatically adds target="_blank" and an icon to external links.
The Component
The component checks if the href is an external URL and conditionally adds target="_blank" and an icon.
<script lang="ts">
import type { HTMLAnchorAttributes } from 'svelte/elements';
let { href, children, ...restProps }: HTMLAnchorAttributes = $props();
const isExternal = $derived(!href.startsWith('/'));
const target = $derived(isExternal ? '_blank' : undefined);
</script>
<a {href} {target} class="text-blue-600 hover:text-blue-800" {...restProps}>
{@render children?.()}
{#if isExternal}
<svg class="ml-1 inline h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
/>
</svg>
{/if}
</a>
The Blueprint
Export the new component from your blueprint.
<script lang="ts" module>
export { default as a } from '$lib/components/a.svelte';
</script>
<!-- ... -->
Usage
Now, all links in your markdown will use this component.
An external link to [Svelte](https://svelte.dev).
An internal link to our [Getting Started](/docs/getting-started) guide.
The first link will open in a new tab with the icon, while the second will be a standard navigation link.
Supported Elements
You can override any standard HTML element tag. Common use cases include:
h1,h2,h3,h4,h5,h6paul,ol,liblockquotecode,preimghrtable,thead,tbody,tr,th,td
Note
When you provide a custom component for pre, it will wrap code blocks. If you provide a code component, it will apply to both inline code and the <code> element inside a <pre> block.