Skip to main content

Copy Button

Add copy buttons to code blocks in your markdown.

Problem

Users can't easily copy code from your markdown code blocks. They have to manually select the text, which is especially difficult on mobile devices.

Solution

Create a custom pre component that automatically adds copy buttons to all code blocks.

Implementation

1. Create the Copy Button Component

src/lib/blueprints/default/copy-button.svelte
		<script lang="ts">
	import type { Snippet } from 'svelte';
 
	let { code, children }: { code: string; children: Snippet } = $props();
 
	let copied = $state(false);
	let buttonText = $derived(copied ? 'Copied!' : 'Copy');
 
	async function copyToClipboard() {
		try {
			await navigator.clipboard.writeText(code);
			copied = true;
			setTimeout(() => {
				copied = false;
			}, 2000);
		} catch (err) {
			console.error('Failed to copy:', err);
		}
	}
</script>
 
<div class="group relative">
	<button
		onclick={copyToClipboard}
		class="absolute right-2 top-2 rounded bg-gray-700 px-2 py-1 text-xs text-white opacity-0 transition-opacity hover:bg-gray-600 group-hover:opacity-100"
	>
		{buttonText}
	</button>
	{@render children?.()}
</div>
	

2. Create the Custom Pre Component

src/lib/blueprints/default/pre.svelte
		<script lang="ts">
	import type { Snippet } from 'svelte';
	import CopyButton from './copy-button.svelte';
 
	let { children, ...restProps }: { children: Snippet } & Record<string, any> = $props();
 
	let codeContent = $state('');
</script>
 
<CopyButton {codeContent}>
	<pre
		class="relative"
		{...restProps}
		{@attach (node) => {
			codeContent = node.textContent;
		}}>
		{@render children?.()}
	</pre>
</CopyButton>
	

3. Export from Blueprint

src/lib/blueprints/default/blueprint.svelte
		<script lang="ts" module>
	export { default as pre } from '$lib/blueprints/default/pre.svelte';
</script>
 
{@render children?.()}
	

4. Configure MDSX

mdsx.config.js
		import { defineConfig } from 'mdsx';
 
export const mdsxConfig = defineConfig({
	extensions: ['.md'],
	blueprints: {
		default: {
			path: 'src/lib/blueprints/default/blueprint.svelte',
		},
	},
});
	

Usage

Now all your code blocks will automatically have copy buttons:

src/content/example.md
		# My Documentation
 
Here's some JavaScript code:
 
```js
function greet(name) {
	return `Hello, ${name}!`;
}
```
 
And some CSS:
 
```css
.button {
	background: blue;
	color: white;
	padding: 10px;
}
```