React
Snippet e slot in Svelte 5: contenuto riusabile senza componenti
In Svelte 5 uno snippet è markup con un nome: si dichiara con {#snippet}, si esegue con {@render} e sostituisce gli slot mantenendo lo scope del genitore.
In sintesi
- Uno snippet si dichiara con {#snippet nome(...)} e si esegue con {@render nome(...)}.
- Il contenuto fra i tag di un componente arriva come snippet implicito children: è una prop, non uno slot.
- Uno snippet non è un componente: non ha stato proprio, lifecycle o import da un file .js.
In Svelte 5 uno snippet è markup con un nome: si dichiara con {#snippet}, si esegue con {@render} e prende il posto degli slot senza passare da un componente.
Uno snippet è una funzione di markup
La dichiarazione accetta parametri e il render li riceve. Lo snippet resta nello scope in cui è scritto, quindi vede le variabili del componente senza doverle passare come props.
npx sv create snippets-demo
{#snippet card(title, body)}
{title}
{body}
{/snippet}
{@render card("Invoice", "Due on 12 May")}
Per consegnare uno snippet a un figlio lo dichiari come prop, con il tipo Snippet esportato da svelte: è una funzione, quindi si passa come funzione e non come stringa.
import type { Snippet } from "svelte";
let { header, children }: { header: Snippet; children: Snippet } = $props();
{@render header()}
{@render children()}
children prende il posto dello slot di default
Il contenuto scritto fra i tag di un componente arriva come snippet implicito children. Se il genitore non passa niente il figlio non trova il valore, e la resa opzionale {@render children?.()} evita l’errore.
Cosa cambia rispetto agli slot
| Svelte 4 | Svelte 5 | Differenza |
|---|---|---|
| slot | children e @render | Il contenuto è una prop, non un elemento da riempire |
| slot con nome | snippet come prop | Nessun attributo slot nel genitore |
| $slots | children valorizzato | Il controllo è sul valore della prop |
| slot props | parametri dello snippet | Il figlio chiama il markup del genitore con i suoi dati |
Il limite da mettere in conto
Uno snippet non è un componente: non ha stato proprio, non ha lifecycle e non si importa da un file .js. Vive nel markup che lo dichiara, quindi chi lo riceve non può iscriversi ai suoi cambiamenti se non ri-renderizzando.
Errori che si vedono
- Scrivere
{@render card}senza parentesi: il render vuole l’esecuzione, non la funzione. - Cercare
slot="header"nel genitore: con gli snippet il nome è una prop, non un attributo. - Dichiarare lo snippet dentro un
{#if}e usarlo fuori: la dichiarazione vale solo in quel blocco. - Passare uno snippet a un componente che usa ancora
<slot />: le due sintassi non si parlano.
I componenti Svelte del catalogo usano già questa forma: flowbite-svelte e svelte-bits si installano come sorgente, e il blocco faq mostra il caso in cui lo snippet basta. Le runes sono in runes di Svelte 5, i file di rotta in routing e layout in SvelteKit, il confronto in Svelte vs React.
Domande frequenti
Gli slot sono deprecati?
No, ma non convivono con le runes nello stesso componente. In un componente scritto con le runes si usano gli snippet; la sintassi con slot resta per i file in modalità legacy.
Posso usare uno snippet in due componenti?
Sì, passandolo come prop tipizzata Snippet. Non si importa da un altro file: la dichiarazione vive nel markup, quindi il componente che lo possiede lo dichiara e lo consegna.
Come passo dei dati dal figlio allo snippet?
Con i parametri: il figlio chiama {@render row(item)} e ogni voce arriva al markup del genitore. È lo stesso scopo degli slot props, senza l’attributo let.
Perché il contenuto non appare?
Perché nessuno lo esegue: dichiarare uno snippet non stampa nulla. Serve una chiamata {@render nome()} nello stesso scope, oppure il passaggio al figlio che la fa.
Funziona con il rendering sul server?
Sì. Gli snippet sono compilati come funzioni e vengono eseguiti durante il render sul server come nel browser, quindi l’HTML iniziale contiene lo stesso markup.