Svelte and SvelteKit course ยท Module 5: Bindings

Dimension Bindings and Special Bindings

2 min read ยท
In this lesson4

Element Dimensions

<script>
  let w = $state(0);
  let h = $state(0);
  let text = $state('Resize the window!');
</script>

<div
  bind:clientWidth={w}
  bind:clientHeight={h}
  class="box"
>
  <p>{text}</p>
  <p>Dimensions: {w} x {h}px</p>
</div>

<style>
  .box {
    width: 100%;
    height: 200px;
    background: #2a2a4a;
    padding: 1rem;
  }
</style>

Available dimension bindings:

  • clientWidth / clientHeight
  • offsetWidth / offsetHeight

Scroll

<script>
  let scrollY = $state(0);
</script>

<svelte:window bind:scrollY />

<div class="header" class:scrolled={scrollY > 50}>
  Viking Saga
</div>

<style>
  .header {
    position: fixed;
    top: 0;
    transition: background 0.3s;
  }
  .header.scrolled {
    background: rgba(0, 0, 0, 0.8);
  }
</style>

Online/Offline Status

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

<svelte:window bind:online />

<p>Status: {online ? 'Online' : 'Offline'}</p>

Practical Example: Viking Form

<script>
  let warrior = $state({
    name: '',
    rank: 'drengr',
    skills: [],
    bio: ''
  });

  function submit(e) {
    e.preventDefault(); // stop the page reload
    console.log('Saved:', $state.snapshot(warrior));
  }
</script>

<form onsubmit={submit}>
  <label>
    Name:
    <input bind:value={warrior.name} required />
  </label>

  <label>
    Rank:
    <select bind:value={warrior.rank}>
      <option value="drengr">Drengr</option>
      <option value="jarl">Jarl</option>
    </select>
  </label>

  <fieldset>
    <legend>Skills:</legend>
    <label>
      <input type="checkbox" bind:group={warrior.skills} value="sailing" />
      Sailing
    </label>
    <label>
      <input type="checkbox" bind:group={warrior.skills} value="combat" />
      Combat
    </label>
  </fieldset>

  <label>
    Biography:
    <textarea bind:value={warrior.bio}></textarea>
  </label>

  <button type="submit">Save warrior</button>
</form>

The form uses the onsubmit attribute, and e.preventDefault() stops the page reload (in Svelte 4 the |preventDefault modifier did this). $state.snapshot(warrior) turns the reactive object into a plain copy that reads well in the console.

Code for this lesson: App.svelte
<script>
  // DOM bindings - bind:this, bind:clientWidth etc.

  // bind:this only needs a plain variable (used in a function, not in the markup)
  let inputRef;

  // Values shown in the markup must be $state to update the view
  let containerWidth = $state(0);
  let containerHeight = $state(0);
  let scrollY = $state(0);

  function focusInput() {
    inputRef?.focus();
  }

  $effect(() => {
    console.log('Scroll position:', scrollY);
  });
</script>

<svelte:window bind:scrollY />

<main class="dom-demo">
  <h1>DOM Bindings</h1>

  <section>
    <h2>bind:this - element reference</h2>
    <input
      bind:this={inputRef}
      type="text"
      placeholder="Click button to focus"
    />
    <button onclick={focusInput}>Focus input</button>
  </section>

  <section bind:clientWidth={containerWidth} bind:clientHeight={containerHeight}>
    <h2>bind:clientWidth/Height</h2>
    <p>Width: <strong>{Math.round(containerWidth)}px</strong></p>
    <p>Height: <strong>{Math.round(containerHeight)}px</strong></p>
    <p class="hint">Resize the window to see changes</p>
  </section>

  <section>
    <h2>svelte:window - scroll</h2>
    <p>Scroll Y: <strong>{Math.round(scrollY)}px</strong></p>
    <div class="scroll-area">
      <p>Scroll the page down...</p>
      <div class="spacer"></div>
      <p>...and observe the scrollY value</p>
    </div>
  </section>
</main>

<style>
  .dom-demo {
    font-family: 'Georgia', serif;
    max-width: 600px;
    margin: 0 auto;
    padding: 2rem;
    background: #1a0f0a;
    color: #e8d5b7;
    min-height: 150vh;
  }

  h1 {
    color: #d4af37;
    text-align: center;
    position: sticky;
    top: 0;
    background: #1a0f0a;
    padding: 1rem 0;
  }

  section {
    background: rgba(212, 175, 55, 0.1);
    border: 1px solid #d4af37;
    border-radius: 8px;
    padding: 1rem;
    margin: 1rem 0;
  }

  h2 {
    color: #d4af37;
    font-size: 1rem;
    margin-top: 0;
  }

  input {
    width: 100%;
    padding: 0.75rem;
    background: rgba(0,0,0,0.3);
    border: 1px solid #3d2914;
    border-radius: 4px;
    color: #e8d5b7;
    margin-bottom: 0.5rem;
  }

  input:focus {
    border-color: #d4af37;
    outline: none;
  }

  button {
    padding: 0.5rem 1rem;
    background: #3d2914;
    color: #e8d5b7;
    border: 1px solid #d4af37;
    border-radius: 4px;
    cursor: pointer;
  }

  button:hover {
    background: #4d3924;
  }

  strong {
    color: #ffd700;
  }

  .hint {
    font-size: 0.85rem;
    color: #8b7355;
    font-style: italic;
  }

  .scroll-area {
    padding: 1rem;
    background: rgba(0,0,0,0.3);
    border-radius: 4px;
  }

  .spacer {
    height: 200px;
  }
</style>

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. How do you track the window's scroll position?

Useful articles