Real-World Component Examples

+15 Mana ✨

Let's build some production-quality components using snippets.

Example 1: Modal

svelte
<!-- Modal.svelte -->
<script>
  let { 
    open = $bindable(false),
    title,
    children,
    footer,
    size = 'medium',
    closeOnBackdrop = true,
    closeOnEscape = true
  } = $props();
  
  function handleKeydown(e) {
    if (closeOnEscape && e.key === 'Escape') {
      open = false;
    }
  }
  
  function handleBackdrop() {
    if (closeOnBackdrop) {
      open = false;
    }
  }
</script>

<svelte:window onkeydown={handleKeydown} />

{#if open}
  <div class="modal-backdrop" onclick={handleBackdrop}>
    <div 
      class="modal modal-{size}" 
      onclick={(e) => e.stopPropagation()}
      role="dialog"
      aria-modal="true"
    >
      <header class="modal-header">
        <h2>{title}</h2>
        <button class="close" onclick={() => open = false}>×</button>
      </header>
      
      <div class="modal-body">
        {@render children?.()}
      </div>
      
      {#if footer}
        <footer class="modal-footer">
          {@render footer()}
        </footer>
      {/if}
    </div>
  </div>
{/if}

Example 2: Data Table

svelte
<!-- DataTable.svelte -->
<script>
  let {
    data,
    columns,
    row,
    empty,
    loading = false,
    sortable = false,
    onSort
  } = $props();
  
  let sortColumn = $state(null);
  let sortDirection = $state('asc');
  
  function handleSort(column) {
    if (sortColumn === column) {
      sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
    } else {
      sortColumn = column;
      sortDirection = 'asc';
    }
    onSort?.({ column, direction: sortDirection });
  }
</script>

<table class="data-table">
  <thead>
    <tr>
      {#each columns as column}
        <th 
          class:sortable
          class:sorted={sortColumn === column.key}
          onclick={() => sortable && handleSort(column.key)}
        >
          {column.label}
          {#if sortable && sortColumn === column.key}
            <span>{sortDirection === 'asc' ? '↑' : '↓'}</span>
          {/if}
        </th>
      {/each}
    </tr>
  </thead>
  <tbody>
    {#if loading}
      <tr>
        <td colspan={columns.length}>
          <div class="loading">Loading...</div>
        </td>
      </tr>
    {:else if data.length === 0}
      <tr>
        <td colspan={columns.length}>
          {#if empty}
            {@render empty()}
          {:else}
            <div class="empty">No data available</div>
          {/if}
        </td>
      </tr>
    {:else}
      {#each data as item, index}
        {@render row(item, index)}
      {/each}
    {/if}
  </tbody>
</table>
svelte
<!-- Usage -->
<DataTable 
  data={users}
  columns={[
    { key: 'name', label: 'Name' },
    { key: 'email', label: 'Email' },
    { key: 'role', label: 'Role' }
  ]}
  sortable
  onSort={handleSort}
>
  {#snippet row(user, index)}
    <tr class:even={index % 2 === 0}>
      <td>{user.name}</td>
      <td>{user.email}</td>
      <td><Badge variant={user.role}>{user.role}</Badge></td>
    </tr>
  {/snippet}
  
  {#snippet empty()}
    <EmptyState>
      <p>No users found</p>
      <Button onclick={addUser}>Add First User</Button>
    </EmptyState>
  {/snippet}
</DataTable>
✓ Completed