or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

real-world-scenarios.mddocs/examples/

Real-World Scenarios

Comprehensive usage examples and patterns for common Svelte development scenarios.

Component Patterns

Form Handling with Validation

<script>
  let form = $state({
    email: '',
    password: '',
    errors: {}
  });
  
  function validate() {
    form.errors = {};
    
    if (!form.email) {
      form.errors.email = 'Email is required';
    } else if (!form.email.includes('@')) {
      form.errors.email = 'Invalid email';
    }
    
    if (!form.password) {
      form.errors.password = 'Password is required';
    } else if (form.password.length < 8) {
      form.errors.password = 'Password must be at least 8 characters';
    }
    
    return Object.keys(form.errors).length === 0;
  }
  
  async function handleSubmit() {
    if (!validate()) return;
    
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          email: form.email,
          password: form.password
        })
      });
      
      if (!response.ok) throw new Error('Login failed');
      
      const data = await response.json();
      console.log('Logged in:', data);
    } catch (error) {
      form.errors.submit = error.message;
    }
  }
</script>

<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
  <input
    type="email"
    bind:value={form.email}
    placeholder="Email"
  />
  {#if form.errors.email}
    <span class="error">{form.errors.email}</span>
  {/if}
  
  <input
    type="password"
    bind:value={form.password}
    placeholder="Password"
  />
  {#if form.errors.password}
    <span class="error">{form.errors.password}</span>
  {/if}
  
  {#if form.errors.submit}
    <span class="error">{form.errors.submit}</span>
  {/if}
  
  <button type="submit">Login</button>
</form>

Data Fetching with Loading States

<script>
  import { onMount } from 'svelte';
  
  let data = $state(null);
  let loading = $state(true);
  let error = $state(null);
  
  onMount(async () => {
    try {
      const response = await fetch('/api/data');
      if (!response.ok) throw new Error('Failed to fetch');
      data = await response.json();
    } catch (e) {
      error = e.message;
    } finally {
      loading = false;
    }
  });
</script>

{#if loading}
  <p>Loading...</p>
{:else if error}
  <p class="error">Error: {error}</p>
{:else if data}
  <pre>{JSON.stringify(data, null, 2)}</pre>
{/if}

Component Composition with Slots

<!-- Card.svelte -->
<div class="card">
  <div class="card-header">
    <slot name="header">Default Header</slot>
  </div>
  <div class="card-body">
    <slot />
  </div>
  <div class="card-footer">
    <slot name="footer" />
  </div>
</div>

<!-- Usage -->
<Card>
  <svelte:fragment slot="header">
    <h2>My Card</h2>
  </svelte:fragment>
  
  <p>Card content goes here</p>
  
  <svelte:fragment slot="footer">
    <button>Action</button>
  </svelte:fragment>
</Card>

Store Patterns

Global State Management

// stores/user.js
import { writable, derived } from 'svelte/store';

export const user = writable(null);
export const isAuthenticated = derived(user, $user => $user !== null);
export const userName = derived(user, $user => $user?.name ?? 'Guest');
<!-- UserProfile.svelte -->
<script>
  import { user, isAuthenticated, userName } from './stores/user.js';
</script>

{#if $isAuthenticated}
  <p>Welcome, {$userName}!</p>
  <button onclick={() => user.set(null)}>Logout</button>
{:else}
  <button onclick={() => user.set({ name: 'John' })}>Login</button>
{/if}

Async Data Store

// stores/api.js
import { readable } from 'svelte/store';

export const apiData = readable(null, (set) => {
  let cancelled = false;
  
  fetch('/api/data')
    .then(r => r.json())
    .then(data => {
      if (!cancelled) set(data);
    })
    .catch(err => {
      if (!cancelled) set({ error: err.message });
    });
  
  return () => {
    cancelled = true;
  };
});

Derived Store with Multiple Sources

// stores/cart.js
import { writable, derived } from 'svelte/store';

export const items = writable([]);
export const taxRate = writable(0.1);

export const subtotal = derived(items, $items =>
  $items.reduce((sum, item) => sum + item.price * item.quantity, 0)
);

export const tax = derived(
  [subtotal, taxRate],
  ([$subtotal, $taxRate]) => $subtotal * $taxRate
);

export const total = derived(
  [subtotal, tax],
  ([$subtotal, $tax]) => $subtotal + $tax
);

Reactivity Patterns

Computed Properties

<script>
  let items = $state([
    { id: 1, name: 'Apple', price: 1.0 },
    { id: 2, name: 'Banana', price: 0.5 },
    { id: 3, name: 'Cherry', price: 2.0 }
  ]);
  
  let filter = $state('');
  let sortBy = $state('name');
  
  let filtered = $derived(
    items.filter(item => 
      item.name.toLowerCase().includes(filter.toLowerCase())
    )
  );
  
  let sorted = $derived.by(() => {
    const sorted = [...filtered];
    sorted.sort((a, b) => {
      if (sortBy === 'name') {
        return a.name.localeCompare(b.name);
      } else {
        return a.price - b.price;
      }
    });
    return sorted;
  });
</script>

<input bind:value={filter} placeholder="Filter..." />
<select bind:value={sortBy}>
  <option value="name">Name</option>
  <option value="price">Price</option>
</select>

<ul>
  {#each sorted as item (item.id)}
    <li>{item.name} - ${item.price}</li>
  {/each}
</ul>

Side Effects with Cleanup

<script>
  let count = $state(0);
  let intervalId;
  
  $effect(() => {
    intervalId = setInterval(() => {
      count++;
    }, 1000);
    
    return () => {
      clearInterval(intervalId);
    };
  });
</script>

<p>Count: {count}</p>

Reactive Window Properties

<script>
  import { windowWidth, windowHeight } from 'svelte/reactivity/window';
  
  let isMobile = $derived($windowWidth < 768);
  let orientation = $derived(
    $windowWidth > $windowHeight ? 'landscape' : 'portrait'
  );
</script>

<p>Width: {$windowWidth}px</p>
<p>Height: {$windowHeight}px</p>
<p>Device: {isMobile ? 'Mobile' : 'Desktop'}</p>
<p>Orientation: {orientation}</p>

Animation Patterns

Spring Animation

<script>
  import { Spring } from 'svelte/motion';
  
  let position = new Spring({ x: 0, y: 0 }, {
    stiffness: 0.1,
    damping: 0.4
  });
  
  function moveTo(x, y) {
    position.set({ x, y });
  }
</script>

<div
  style="transform: translate({$position.current.x}px, {$position.current.y}px)"
  onclick={() => moveTo(Math.random() * 400, Math.random() * 400)}
>
  Click to move
</div>

Transition with Conditions

<script>
  import { fade, fly } from 'svelte/transition';
  
  let show = $state(true);
  let items = $state(['Item 1', 'Item 2', 'Item 3']);
</script>

<button onclick={() => show = !show}>
  Toggle
</button>

{#if show}
  <div transition:fade={{ duration: 300 }}>
    <h2>Content</h2>
  </div>
{/if}

{#each items as item, i (i)}
  <div transition:fly={{ y: 50, duration: 300 }}>
    {item}
  </div>
{/each}

Server-Side Rendering

Express Integration

// server.js
import express from 'express';
import { render } from 'svelte/server';
import App from './App.svelte';

const app = express();

app.get('/', (req, res) => {
  const { head, body } = render(App, {
    props: {
      user: req.user,
      data: getInitialData()
    }
  });
  
  res.send(`
    <!DOCTYPE html>
    <html>
      <head>${head}</head>
      <body>${body}</body>
    </html>
  `);
});

Hydration

// client.js
import { hydrate } from 'svelte';
import App from './App.svelte';

const app = hydrate(App, {
  target: document.getElementById('app'),
  props: {
    user: window.__INITIAL_USER__,
    data: window.__INITIAL_DATA__
  }
});

Context API

Theme Provider

<!-- ThemeProvider.svelte -->
<script>
  import { setContext } from 'svelte';
  
  let { theme = 'light' } = $props();
  
  setContext('theme', {
    current: $derived(theme),
    toggle: () => {
      theme = theme === 'light' ? 'dark' : 'light';
    }
  });
</script>

<div class="theme-{theme}">
  <slot />
</div>

<!-- Usage -->
<script>
  import { getContext } from 'svelte';
  
  const theme = getContext('theme');
</script>

<button onclick={theme.toggle}>
  Current theme: {$theme.current}
</button>

Actions

Click Outside Detection

// actions/clickOutside.js
export function clickOutside(node, callback) {
  function handleClick(event) {
    if (!node.contains(event.target)) {
      callback(event);
    }
  }
  
  document.addEventListener('click', handleClick, true);
  
  return {
    destroy() {
      document.removeEventListener('click', handleClick, true);
    }
  };
}
<script>
  import { clickOutside } from './actions/clickOutside.js';
  
  let show = $state(false);
</script>

<div use:clickOutside={() => show = false}>
  <button onclick={() => show = !show}>Toggle</button>
  {#if show}
    <div class="dropdown">Content</div>
  {/if}
</div>

Auto-Resize Textarea

// actions/autoResize.js
export function autoResize(node) {
  function resize() {
    node.style.height = 'auto';
    node.style.height = node.scrollHeight + 'px';
  }
  
  resize();
  node.addEventListener('input', resize);
  
  return {
    update() {
      resize();
    },
    destroy() {
      node.removeEventListener('input', resize);
    }
  };
}
<script>
  import { autoResize } from './actions/autoResize.js';
  
  let text = $state('');
</script>

<textarea bind:value={text} use:autoResize></textarea>