Svelte
05 / 07

Advanced Features

Svelte Advanced Features

Explore advanced Svelte features including lifecycle, actions, special elements, and compiler optimizations:

Lifecycle Functions

<script>
  import { onMount, onDestroy, beforeUpdate, afterUpdate, tick } from 'svelte';
  
  let data;
  
  // Runs after component first renders
  onMount(async () => {
    console.log('Component mounted');
    
    const response = await fetch('/api/data');
    data = await response.json();
    
    // Return cleanup function
    return () => {
      console.log('Cleanup on unmount');
    };
  });
  
  // Runs just before DOM updates
  beforeUpdate(() => {
    console.log('About to update DOM');
  });
  
  // Runs after DOM updates
  afterUpdate(() => {
    console.log('DOM updated');
  });
  
  // Runs when component is destroyed
  onDestroy(() => {
    console.log('Component destroyed');
    // Cleanup subscriptions, timers, etc.
  });
  
  // Wait for pending state changes
  async function updateAndFocus() {
    count += 1;
    await tick();  // Wait for DOM update
    inputElement.focus();
  }
</script>

Actions

Actions are functions that are called when an element is created. They can be used to add custom behavior to elements.

<script>
  // Click outside action
  function clickOutside(node) {
    const handleClick = (event) => {
      if (!node.contains(event.target)) {
        node.dispatchEvent(new CustomEvent('outclick'));
      }
    };
    
    document.addEventListener('click', handleClick, true);
    
    return {
      destroy() {
        document.removeEventListener('click', handleClick, true);
      }
    };
  }
  
  // Tooltip action with parameters
  function tooltip(node, text) {
    let tooltipElement;
    
    function mouseenter() {
      tooltipElement = document.createElement('div');
      tooltipElement.textContent = text;
      tooltipElement.className = 'tooltip';
      document.body.appendChild(tooltipElement);
      
      const rect = node.getBoundingClientRect();
      tooltipElement.style.top = `${rect.bottom + 5}px`;
      tooltipElement.style.left = `${rect.left}px`;
    }
    
    function mouseleave() {
      if (tooltipElement) {
        tooltipElement.remove();
        tooltipElement = null;
      }
    }
    
    node.addEventListener('mouseenter', mouseenter);
    node.addEventListener('mouseleave', mouseleave);
    
    return {
      update(newText) {
        text = newText;
      },
      destroy() {
        node.removeEventListener('mouseenter', mouseenter);
        node.removeEventListener('mouseleave', mouseleave);
        if (tooltipElement) tooltipElement.remove();
      }
    };
  }
  
  let isOpen = false;
  let tooltipText = 'Hover over me';
</script>

<div use:clickOutside on:outclick={() => isOpen = false}>
  <button on:click={() => isOpen = true}>Open Menu</button>
  {#if isOpen}
    <div class="menu">Menu content</div>
  {/if}
</div>

<p use:tooltip={tooltipText}>Hover for tooltip</p>

Special Elements

<script>
  import Component from './Component.svelte';
  
  let currentComponent = Component;
  let components = [ComponentA, ComponentB, ComponentC];
  let selectedIndex = 0;
</script>

<!-- svelte:component - dynamic component -->
<svelte:component this={currentComponent} prop="value" />
<svelte:component this={components[selectedIndex]} />

<!-- svelte:self - recursive component -->
<script>
  export let items = [];
</script>

{#each items as item}
  <div>{item.name}</div>
  {#if item.children}
    <svelte:self items={item.children} />
  {/if}
{/each}

<!-- svelte:window - window events -->
<svelte:window
  on:keydown={(e) => console.log(e.key)}
  on:resize={(e) => console.log('Resized')}
  bind:scrollY={y}
  bind:innerWidth={width}
/>

<!-- svelte:body - body events -->
<svelte:body on:mouseenter={handleMouseEnter} />

<!-- svelte:head - modify document head -->
<svelte:head>
  <title>Page Title</title>
  <meta name="description" content="Page description" />
</svelte:head>

<!-- svelte:options - compiler options -->
<svelte:options immutable={true} />
<svelte:options accessors={true} />

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free