Skip to main content

bind:

データは通常、親から子へと流れますが、bind: ディレクティブを使用すると、データを子から親へ流すことができます。

一般的な構文は bind:property={expression} であり、expressionlvalue (つまり、変数やオブジェクトのプロパティ) です。式がプロパティと同じ名前の識別子である場合、式を省略することができます — 言い換えると、以下は等価です:

<input bind:value={value} />
<input bind:value />

Svelte は、バインドされた値を更新するイベントリスナーを作成します。要素が既に同じイベントのリスナーを持っている場合、そのリスナーはバインドされた値が更新される前に実行されます。

ほとんどのバインディングは 双方向 であり、値の変更が要素に影響し、その逆も同様です。一部のバインディングは 読み取り専用 であり、値を変更しても要素に影響を与えません。

Function bindings

bind:property={get, set} を使用して、getset を関数として指定し、バリデーションや変換を行うことができます:

<input bind:value={
	() => value,
	(v) => value = v.toLowerCase()}
/>

dimension bindings のような読み取り専用バインディングの場合、get の値は null にする必要があります:

<div
	bind:clientWidth={null, redraw}
	bind:clientHeight={null, redraw}
>...</div>

Function bindings は Svelte 5.9.0 以降で使用可能です。

<input bind:value>

<input> 要素に対する bind:value ディレクティブは、input の value プロパティをバインドします:

<script>
	let message = $state('hello');
</script>

<input bind:value={message} />
<p>{message}</p>

数値を扱う input (type="number" または type="range") の場合、値は数値に変換されます (デモ):

<script>
	let a = $state(1);
	let b = $state(2);
</script>

<label>
	<input type="number" bind:value={a} min="0" max="10" />
	<input type="range" bind:value={a} min="0" max="10" />
</label>

<label>
	<input type="number" bind:value={b} min="0" max="10" />
	<input type="range" bind:value={b} min="0" max="10" />
</label>

<p>{a} + {b} = {a + b}</p>

入力が空または無効 (type="number" の場合) の場合、値は undefined になります。

バージョン 5.6.0 以降、<input>defaultValue が設定されていてフォームの一部である場合、フォームがリセットされると空文字列ではなくその値に戻ります。初回のレンダリングでは、バインディングの値が null または undefined でない限り優先されることに注意してください。

<script>
	let value = $state('');
</script>

<form>
	<input bind:value defaultValue="not the empty string">
	<input type="reset" value="Reset">
</form>

リセットボタンは慎重に使用し、ユーザーがフォームを送信しようとしているときに誤ってクリックしないようにしてください。

<input bind:checked>

checkbox および radio の input には、bind:checked を使用してバインドできます:

<label>
	<input type="checkbox" bind:checked={accepted} />
	Accept terms and conditions
</label>

バージョン 5.6.0 以降、<input>defaultChecked 属性が設定されておりフォームの一部である場合、フォームがリセットされると false ではなくその値に戻ります。初回のレンダリングでは、バインディングの値が null または undefined でない限り優先されます。

<script>
	let checked = $state(true);
</script>

<form>
	<input type="checkbox" bind:checked defaultChecked={true}>
	<input type="reset" value="Reset">
</form>

<input bind:group>

相互に動作する input は、bind:group を使用できます。

<script>
	let tortilla = $state('Plain');

	/** @type {Array<string>} */
	let fillings = $state([]);
</script>

<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={tortilla} value="Plain" />
<input type="radio" bind:group={tortilla} value="Whole wheat" />
<input type="radio" bind:group={tortilla} value="Spinach" />

<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={fillings} value="Rice" />
<input type="checkbox" bind:group={fillings} value="Beans" />
<input type="checkbox" bind:group={fillings} value="Cheese" />
<input type="checkbox" bind:group={fillings} value="Guac (extra)" />

bind:group は、input が同じ Svelte コンポーネント内にある場合にのみ機能します。

<input bind:files>

type="file" を持つ <input> 要素では、bind:files を使用して 選択されたファイルの FileList を取得できます。プログラムでファイルを更新する場合、常に FileList オブジェクトを使用する必要があります。現在、FileList オブジェクトは直接作成できないため、新しい DataTransfer オブジェクトを作成し、そこから files を取得する必要があります。

<script>
	let files = $state();

	function clear() {
		files = new DataTransfer().files; // null or undefined does not work
	}
</script>

<label for="avatar">Upload a picture:</label>
<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" />
<button onclick={clear}>clear</button>

FileList オブジェクトも変更できないため、例えばリストから単一のファイルを削除したい場合は、新しい DataTransfer オブジェクトを作成し、保持したいファイルを追加する必要があります。

DataTransfer はサーバーサイドの JS ランタイムでは利用できない場合があります。files にバインドされた state を未初期化のままにしておくことで、コンポーネントがサーバーサイドレンダリングされる際の潜在的なエラーを防ぐことができます。

<select bind:value>

<select> の値のバインディングは、選択された <option>value プロパティに対応しており、これは通常の DOM での場合と異なり、文字列だけでなく任意の値を使用できます。

<select bind:value={selected}>
	<option value={a}>a</option>
	<option value={b}>b</option>
	<option value={c}>c</option>
</select>

<select multiple> 要素は、チェックボックスグループと同様に動作します。バインドされた変数は、選択された各 <option>value プロパティに対応するエントリを持つ配列です。

<select multiple bind:value={fillings}>
	<option value="Rice">Rice</option>
	<option value="Beans">Beans</option>
	<option value="Cheese">Cheese</option>
	<option value="Guac (extra)">Guac (extra)</option>
</select>

<option> の値がそのテキストコンテンツと一致する場合、その属性は省略できます。

<select multiple bind:value={fillings}>
	<option>Rice</option>
	<option>Beans</option>
	<option>Cheese</option>
	<option>Guac (extra)</option>
</select>

<select> にデフォルト値を設定するには、初期選択すべき <option> (または <select multiple> の場合は複数の <option>) に selected 属性を追加します。<select> がフォームの一部である場合、フォームがリセットされるとその選択に戻ります。初回レンダリング時には、バインディングの値が undefined でない限り優先されます。

<select bind:value={selected}>
	<option value={a}>a</option>
	<option value={b} selected>b</option>
	<option value={c}>c</option>
</select>

<audio>

<audio> 要素には、以下の5つの双方向バインディングがあります:

...および以下の6つの読み取り専用バインディングがあります:

<audio src={clip} bind:duration bind:currentTime bind:paused></audio>

<video>

<video> 要素には、<audio> 要素と同じバインディングがすべて含まれ、さらに読み取り専用の videoWidth および videoHeight バインディングがあります。

<img>

<img> 要素には、以下の2つの読み取り専用バインディングがあります:

<details bind:open>

<details> 要素は、open プロパティへのバインディングをサポートします。

<details bind:open={isOpen}>
	<summary>How do you comfort a JavaScript bug?</summary>
	<p>You console it.</p>
</details>

Contenteditable bindings

contenteditable 属性を持つ要素は、以下のバインディングをサポートします:

innerTexttextContent には微妙な違いがあります

<div contenteditable="true" bind:innerHTML={html} />

Dimensions

すべての visible な要素には、以下の読み取り専用バインディングがあり、これらは ResizeObserver を使用して測定されます:

<div bind:offsetWidth={width} bind:offsetHeight={height}>
	<Chart {width} {height} />
</div>

display: inline 要素には width や height がありません (<img><canvas> のような「固有の」 dimension を持つ要素を除く)。そのため、ResizeObserver で観測することはできません。これらの要素の display スタイルを inline-block などに変更する必要があります。

bind:this

bind:this={dom_node}

DOM ノードへの参照を取得するには、bind:this を使用します。この値はコンポーネントがマウントされるまで undefined のままです — 言い換えると、初期化時ではなく、effect やイベントハンドラー内で読み取る必要があります:

<script>
	/** @type {HTMLCanvasElement} */
	let canvas;

	$effect(() => {
		const ctx = canvas.getContext('2d');
		drawStuff(ctx);
	});
</script>

<canvas bind:this={canvas} />

コンポーネントも bind:this をサポートしており、プログラムでコンポーネントインスタンスを操作できます。

App
<ShoppingCart bind:this={cart} />

<button onclick={() => cart.empty()}> Empty shopping cart </button>
ShoppingCart
<script>
	// All instance exports are available on the instance object
	export function empty() {
		// ...
	}
</script>
<script lang="ts">
	// All instance exports are available on the instance object
	export function empty() {
		// ...
	}
</script>

bind:property for components

bind:property={variable}

要素と同じ構文を使用して、コンポーネントの props にバインドできます。

<Keypad bind:value={pin} />

Svelte の props はバインディングなしでもリアクティブですが、そのリアクティビティはデフォルトでコンポーネント内にのみ流れます。bind:property を使用すると、コンポーネント内から props の変更をコンポーネント外に流すことができます。

props がバインド可能なものとしてマークするには、$bindable rune を使用します:

<script>
	let { readonlyProperty, bindableProperty = $bindable() } = $props();
</script>

props をバインド可能として宣言することは、それが bind: を使用できることを意味しますが、bind: を使用しなければならないことを意味するわけではありません。

bindable な props にはフォールバック値を設定できます:

<script>
	let { bindableProperty = $bindable('fallback value') } = $props();
</script>

このフォールバック値は、props がバインドされていない場合にのみ適用されます。props がバインドされていてフォールバック値が存在する場合、親コンポーネントは undefined 以外の値を提供する必要があります。そうでない場合、ランタイムエラーが発生します。これにより、どの値が適用されるかが不明確な状況になるのを防ぎます。

Edit this page on GitHub

previous next