Skip to main content

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:

src/lib/components/h1.svelte
		<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.

src/lib/blueprints/default.svelte
		<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.

src/lib/components/a.svelte
		<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.

src/lib/blueprints/default.svelte
		<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.

content/index.md
		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, h6
  • p
  • a
  • ul, ol, li
  • blockquote
  • code, pre
  • img
  • hr
  • table, thead, tbody, tr, th, td