Skip to main content

{@attach ...}

Attachments are functions that run when an element is mounted to the DOM. Optionally, they can return a function that is called when the element is later removed from the DOM.

Attachments are available in Svelte 5.29 and newer.

App
<script>
	/** @type {import('svelte/attachments').Attachment} */
	function myAttachment(element) {
		console.log(element.nodeName); // 'DIV'

		return () => {
			console.log('cleaning up');
		};
	}
</script>

<div {@attach myAttachment}>...</div>
<script lang="ts">
	import type { Attachment } from 'svelte/attachments';


	const myAttachment: Attachment = (element) => {
		console.log(element.nodeName); // 'DIV'

		return () => {
			console.log('cleaning up');
		};
	};
</script>

<div {@attach myAttachment}>...</div>

An element can have any number of attachments.

Attachment factories

A useful pattern is for a function, such as tooltip in this example, to return an attachment (demo):

App
<script>
	import tippy from 'tippy.js';

	let content = $state('Hello!');

	/**
	 * @param {string} content
	 * @returns {import('svelte/attachments').Attachment}
	 */
	function tooltip(content) {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<button {@attach tooltip(content)}>
	Hover me
</button>
<script lang="ts">
	import tippy from 'tippy.js';
	import type { Attachment } from 'svelte/attachments';

	let content = $state('Hello!');

	function tooltip(content: string): Attachment {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<button {@attach tooltip(content)}>
	Hover me
</button>

Since the tooltip(content) expression runs inside an effect, the attachment will be destroyed and recreated whenever content changes.

Inline attachments

Attachments can also be created inline (demo):

App
<script>
	import { paint } from './gradient.js';
</script>

<canvas
	width={32}
	height={32}
	{@attach (canvas) => {
		const context = canvas.getContext('2d');

		$effect(() => {
			let frame = requestAnimationFrame(function loop(t) {
				frame = requestAnimationFrame(loop);
				paint(context, t);
			});

			return () => {
				cancelAnimationFrame(frame);
			};
		});
	}}
></canvas>
<script lang="ts">
	import { paint } from './gradient.js';
</script>

<canvas
	width={32}
	height={32}
	{@attach (canvas) => {
		const context = canvas.getContext('2d');

		$effect(() => {
			let frame = requestAnimationFrame(function loop(t) {
				frame = requestAnimationFrame(loop);
				paint(context, t);
			});

			return () => {
				cancelAnimationFrame(frame);
			};
		});
	}}
></canvas>

Passing attachments to components

When used on a component, {@attach ...} will create a prop whose key is a Symbol. If the component then spreads props onto an element, the element will receive those attachments.

This allows you to create wrapper components that augment elements (demo):

Button
<script>
	/** @type {import('svelte/elements').HTMLButtonAttributes} */
	let { children, ...props } = $props();
</script>

<!-- `props` includes attachments -->
<button {...props}>
	{@render children?.()}
</button>
<script lang="ts">
	import type { HTMLButtonAttributes } from 'svelte/elements';

	let { children, ...props }: HTMLButtonAttributes = $props();
</script>

<!-- `props` includes attachments -->
<button {...props}>
	{@render children?.()}
</button>
App
<script>
	import tippy from 'tippy.js';
	import Button from './Button.svelte';

	let content = $state('Hello!');

	/**
	 * @param {string} content
	 * @returns {import('svelte/attachments').Attachment}
	 */
	function tooltip(content) {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<Button {@attach tooltip(content)}>
	Hover me
</Button>
<script lang="ts">
	import tippy from 'tippy.js';
	import Button from './Button.svelte';
	import type { Attachment } from 'svelte/attachments';

	let content = $state('Hello!');

	function tooltip(content: string): Attachment {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<Button {@attach tooltip(content)}>
	Hover me
</Button>

Creating attachments programmatically

To add attachments to an object that will be spread onto a component or element, use createAttachmentKey.

Edit this page on GitHub llms.txt