Svelte 5 Snippets: Reusable Components with createRawSnippet

Tuesday, November 12, 2024
11 min read

With Svelte 5, the Snippet feature and createRawSnippet function provide reducing code duplication and adding more functionality into our Svelte apps. This guide explores how to leverage these powerful tools to create clean, maintainable, and efficient code.

What Are Snippets in Svelte 5?

A Snippet is a small block of code that allows you to reuse repetitive code fragments. Svelte 5’s snippet feature enables iterating frequently used HTML elements, and use them programmatically better way.

Advantages of Snippets

  • Reduces Code Duplication: Instead of writing the same code block repeatedly, you can define it in one place using a snippet.
  • Simplifies Maintenance: Update the snippet in one place, and all instances where the snippet is used will automatically reflect the changes.
  • Improves Code Readability: Cleaner components with less repetitive code make your project easier to understand and navigate.

Understanding the createRawSnippet Function

The createRawSnippet function in Svelte 5 is a powerful tool designed to create custom snippets. This function allows you to define how the snippet is rendered and how it behaves in various contexts, offering flexibility and control over your reusable components.

Basic Usage of createRawSnippet

Here’s a simple example demonstrating how to create a dynamic greeting message using createRawSnippet:

import { createRawSnippet } from 'svelte';

const greet = createRawSnippet((name) => {
  return {
    render: () => `
      <h1>Hello ${name()}!</h1>
    `,
    setup: (node) => {
      $effect(() => {
        node.textContent = `Hello ${name()}!`;
      });
    }
  };
});


{@render greet("Alice")}

Output:

<h1>Hello Alice</h1>

In this example:

  1. Snippet Creation: The greet snippet is created using createRawSnippet, which takes the name as a parameter and returns the HTML structure along with a setup function to manage reactive updates.
  2. Snippet Usage: The snippet is rendered using {@render greet(name)}, and shown as a welcoming message for the user.

Advanced Snippet Example

In more complex projects, snippets may require more parameters and functionality. It’s like micro components. Below is an advanced example where the greeting adapts based on the time of day.

<script>
  import { createRawSnippet } from "svelte";

  const greet = createRawSnippet((name) => {
    return {
      setup: (node) => {
        $effect(() => {
          const currentHour = new Date().getHours();
          let timeOfDayGreeting = "";

          if (currentHour < 12) {
            timeOfDayGreeting = "Good Morning";
          } else if (currentHour < 18) {
            timeOfDayGreeting = "Good Afternoon";
          } else {
            timeOfDayGreeting = "Good Evening";
          }

          node.textContent = `${timeOfDayGreeting}, ${name()}!`;

          return () => console.log("unmounted");
        });
      },
      render: () => `<p>${name()}!</p>`,
    };
  });
</script>

{@render greet("Alice")}

Output (depending on the time of day):

<p>Good Afternoon, Alice!</p>

Explanation:

  • The greet snippet not only renders a greeting but also dynamically updates the message based on the current time, showcasing how snippets can incorporate more complex logic.

Practical Use Cases for Snippets in Svelte 5

To use the snippet feature effectively, follow some use cases below.

1. Reusing Common UI Structures

If your project frequently uses similar UI components, such as user cards or action buttons, snippets can help streamline their implementation.

<script>
  import { createRawSnippet } from 'svelte';
  import { writable } from 'svelte/store';

  const users = writable([
    { name: 'Alice', role: 'Developer' },
    { name: 'Bob', role: 'Designer' },
    { name: 'Charlie', role: 'Manager' }
  ]);

  const userCard = createRawSnippet((user) => {
    return {
      render: () => `
        <div class="card">
          <h2 class="text-lg font-bold">${user.name}</h2>
          <p class="text-sm text-gray-600">${user.role}</p>
        </div>
      `,
    };
  });
</script>

<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
  {#each $users as user}
    {@render userCard(user)}
  {/each}
</div>

2. Managing CSS and Styles

Snippets can also help manage and apply consistent styling across your components, ensuring a uniform look and feel.

<script>
  import { createRawSnippet } from 'svelte';
  import { writable } from 'svelte/store';

  const actions = writable([
    { label: 'Save', style: 'bg-green-500 text-white' },
    { label: 'Delete', style: 'bg-red-500 text-white' },
    { label: 'Cancel', style: 'bg-gray-300 text-black' }
  ]);

  const actionButton = createRawSnippet((label, style) => {
    return {
      render: () => `
        <button class="py-2 px-4 rounded ${style}">
          ${label}
        </button>
      `,
    };
  });
</script>

<div class="flex space-x-2">
  {#each $actions as action}
    {@render actionButton(action.label, action.style)}
  {/each}
</div>

3. UI Testing with createRawSnippet

The createRawSnippet function also can be used for UI testing as well.

<script>
  let count = $state(0);
  const increment = () => {
    count += 1;
  };
</script>

<button onclick={increment}>{count}</button>
import { createRawSnippet, mount, unmount } from 'svelte';
import { describe, expect, it } from 'vitest';
import Counter from './Counter.svelte';
import { render, screen } from '@testing-library/svelte';

const counterSnippet = createRawSnippet(() => {
    return {
      setup: (target) => {
        const comp = mount(Counter, { target });
		return () => unmount(comp);
      },
      render: () => `<div></div>`,
    };
  });


describe('Counter', () => {
	it('Check initial counter value', () => {
		// container is a parent element of our counter component
		const container = render(counterSnippet).container;

		// we selected the button element
		const counter = container.querySelector("button");

		// get the value of the counter
		const count = counter.innerHTML;

		// we expect the value to be 0
		expect(count).toBe("0");
		
		// for visual debugging
		screen.debug();
	});
});

This last example show how snippets can be used for UI testing with Svelte 5 and Vitest.

Final Thoughts

The snippet concept, one of the new Svelte 5 features, offers developers faster code development and freedom. Instead of creating files for each component over and over again, we can provide functionality in this way. Advanced use is also possible with createRawSnippet.