Skip to main content

{@attach ...}

Attachment は要素がDOMにマウントされたとき、または関数内で読み取られる state が更新されたときに、 effect 内で実行される関数です。

オプションとして、 attachment が再実行される前、または要素がDOMから削除された後に呼び出される関数を返すこともできます。

attachment は Svelte 5.29 以降で利用できます。

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>

ひとつの要素はいくつでも attachment を持つことができます。

Attachmentファクトリ

便利なパターンとして、例にある tooltip のような関数が attachment を返す方法があります(デモ):

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>

tooltip(content) 式は effect 内で実行されるため、 content が変更されるたびに attachment は破棄され再作成されます。attachment 関数の 内部 で読み取られた state についても、最初に実行されたときに同じことが起こります。 (これが望ましくないときは、 Attachment の再実行タイミングを制御する を参照してください。)

インライン attachment

Attachments はインラインで作成することもできます (デモ):

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

		$effect(() => {
			context.fillStyle = color;
			context.fillRect(0, 0, canvas.width, canvas.height);
		});
	}}
></canvas>

ネストされた effect は color が変更されるたびに実行されますが、外部の effect (canvas.getContext(...) が呼び出される箇所) はリアクティブな state を読み取らないため、一度しか実行されません。

コンポーネントへの attachment の受け渡し

コンポーネントで {@attach ...} を使うと、キーが Symbol の props を作成します。コンポーネントが props を要素に 展開(spreads) すると、その要素は展開された attachment を受け取ります。

これにより、要素を拡張する ラッパーコンポーネント を作成できます (デモ):

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

<!-- `props` には attachment が含まれます -->
<button {...props}>
	{@render children?.()}
</button>
<script lang="ts">
	import type { HTMLButtonAttributes } from 'svelte/elements';

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

<!-- `props` には attachment が含まれます -->
<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>

Attachment の再実行タイミングを制御する

attachment は actions と異なり、完全にリアクティブです。 {@attach foo(bar)}foo または bar (あるいは foo の内部で読み取られた state) の変更で再実行されます:

function function foo(bar: any): (node: any) => voidfoo(bar) {
	return (node) => {
		veryExpensiveSetupWork(node: anynode);
		update(node: anynode, bar: anybar);
	};
}

まれにこれが問題になるとき(例えば foo が高コストかつ避けられないセットアップ作業をするときなど)には、データを関数内で渡し、子 effect で読み取ることを検討してください:

function function foo(getBar: any): (node: any) => voidfoo(getBar) {
	return (node) => {
		veryExpensiveSetupWork(node: anynode);

		
function $effect(fn: () => void | (() => void)): void
namespace $effect

Runs code when a component is mounted to the DOM, and then whenever its dependencies change, i.e. $state or $derived values. The timing of the execution is after the DOM has been updated.

Example:

$effect(() => console.log('The count is now ' + count));

If you return a function from the effect, it will be called right before the effect is run again, or when the component is unmounted.

Does not run during server-side rendering.

https://svelte.dev/docs/svelte/$effect

@paramfn The function to execute
$effect
(() => {
update(node: anynode, getBar: anygetBar()); }); } }

プログラムによる attachment の作成

コンポーネントや要素に展開されるオブジェクトに attachment を追加するには、 createAttachmentKey を使います。

action から attachment への変換

action のみを提供するライブラリを使用している場合、 fromAction で action を attachment に変換できます。これにより、(例えば)コンポーネントで使えるようになります。

Edit this page on GitHub llms.txt