bind:
データは通常、親から子へと流れますが、bind:
ディレクティブを使用すると、データを子から親へ流すことができます。
一般的な構文は bind:property={expression}
であり、expression
は lvalue (つまり、変数やオブジェクトのプロパティ) です。式がプロパティと同じ名前の識別子である場合、式を省略することができます — 言い換えると、以下は等価です:
<input bind:value={value} />
<input bind:value />
Svelte は、バインドされた値を更新するイベントリスナーを作成します。要素が既に同じイベントのリスナーを持っている場合、そのリスナーはバインドされた値が更新される前に実行されます。
ほとんどのバインディングは 双方向 であり、値の変更が要素に影響し、その逆も同様です。一部のバインディングは 読み取り専用 であり、値を変更しても要素に影響を与えません。
Function bindings
bind:property={get, set}
を使用して、get
と set
を関数として指定し、バリデーションや変換を行うことができます:
<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
属性を持つ要素は、以下のバインディングをサポートします:
<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
をサポートしており、プログラムでコンポーネントインスタンスを操作できます。
<ShoppingCart bind:this={cart} />
<button onclick={() => cart.empty()}> Empty shopping cart </button>
<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
以外の値を提供する必要があります。そうでない場合、ランタイムエラーが発生します。これにより、どの値が適用されるかが不明確な状況になるのを防ぎます。