Templates
Alguns componentes têm uma estrutura interna fixa — um card sempre tem título, corpo e rodapé, numa ordem específica. Templates permitem definir essa estrutura uma vez e reutilizá-la em qualquer lugar.
O problema que templates resolvem
Imagine um componente @card que você quer usar assim:
```seed
@card
@title
Bem-vindo ao Seed
@body
Uma ferramenta simples para criar páginas HTML.
@footer
@button variant=primary
Começar agora
```Sem template, o Seed não saberia onde colocar o título, onde colocar o corpo, qual tag usar para cada parte, ou qual ordem seguir no HTML final.
O template resolve isso: é um arquivo (ou um trecho no YAML) que descreve a estrutura interna do componente — quais partes existem, em que ordem aparecem, e com quais classes.
Como funciona na prática
O template do @card acima seria algo assim:
```seed
@div class=p-6 border-b
{title}
@div class=p-6 flex-1
{?body}
@div class=p-6 border-t
{?footer}
```As marcações entre chaves — {title}, {?body}, {?footer} — são os espaços reservados. Cada um tem um nome, e o Seed substitui cada espaço pelo conteúdo correspondente que você passou no .seed.
Resultado: o conteúdo de @title vai para dentro do <div class="p-6 border-b"> do template. Sem você precisar lembrar da estrutura — ela está garantida pelo template.
Espaços obrigatórios e opcionais
Note que {title} não tem ? e {?body}, {?footer} têm. Essa é a diferença entre espaço obrigatório e opcional:
| Sintaxe | Significa | Se não for preenchido |
|---|---|---|
{title} | Obrigatório | Aparece um aviso amarelo no HTML para você perceber o erro |
{?body} | Opcional (note o ?) | Simplesmente não aparece — nenhum HTML extra gerado |
{?children} | Opcional — pega tudo que sobrar | Se não houver conteúdo extra, não aparece nada |
O {?children} é especial: ele captura qualquer conteúdo que você passou mas que não tem um espaço reservado com aquele nome. Útil quando o componente aceita conteúdo livre além das partes nomeadas.
Detalhe importante: se um espaço opcional está dentro de um elemento HTML e ninguém preencheu, o elemento inteiro desaparece — não fica uma <div> vazia no HTML.
Como o conteúdo chega ao template
No seu arquivo .seed, cada filho direto do componente com um nome que bate com um espaço reservado é encaminhado para aquele espaço:
```seed
@card
@title ← vai para {title} no template
Título do card
@body ← vai para {?body} no template
Descrição aqui.
← @footer foi omitido: {?footer} não aparece no HTML
```A ordem que você escreve no .seed não importa — o HTML final sempre segue a ordem definida no template. Você pode colocar @footer antes de @title no .seed que o HTML ainda vai sair com título primeiro, rodapé por último.
Definindo o template
Você pode definir o template de duas formas — o resultado é idêntico, é só uma questão de organização:
Opção 1 — inline no YAML
Tudo em um único arquivo. Prático para componentes simples:
```yaml
card:
tag: div
class: bg-white rounded-xl border border-gray-200
variant:
elevated: shadow-lg border-0
template: |
@div class=p-6 border-b
{title}
@div class=p-6 flex-1
{?body}
@div class=p-6 border-t
{?footer}
```Opção 2 — arquivo separado
Um arquivo card.template ao lado do card.yaml. Melhor para templates longos ou quando você quer editar com syntax highlighting:
```
src/components/
card/
card.yaml ← define tag, classes, variantes
card.template ← define a estrutura interna
```O Seed associa automaticamente o card.template ao componente card porque estão na mesma pasta. Você não precisa configurar nada.
Templates alternativos
Um componente pode ter mais de um template — útil quando você quer o mesmo componente em layouts diferentes (vertical, horizontal, compacto, etc.):
```yaml
card:
tag: div
class: bg-white rounded-xl border border-gray-200
template:
default: |
@div class=p-6
{title}
{?body}
horizontal: |
@div class=flex gap-6
@div class=w-1/3
{?image}
@div class=flex-1 p-6
{title}
{?body}
```Para usar o template alternativo, passe template= como prop:
```seed
@card template=horizontal
@image
@img src=foto.jpg
@title
Título
@body
Descrição do card.
```Com arquivo separado, coloque horizontal.template na mesma pasta que card.yaml. O nome do arquivo antes de .template vira o nome da variante.
Criando um componente com template do zero
Exemplo completo: um componente feature com ícone, título e descrição.
1. Defina o componente no YAML (src/components/feature/feature.yaml):
```yaml
feature:
tag: div
class: flex gap-6 items-start
variant:
centered: flex-col items-center text-center
template: |
@div class=w-12 h-12 rounded-xl bg-blue-100 flex items-center justify-center shrink-0
{?icon}
@div
@h3 class=font-semibold text-lg mb-1
{title}
@p class=text-gray-600 text-sm
{?description}
```2. Use no .seed:
```seed
@features-item variant=centered
@icon
✨
@title
Recurso incrível
@description
Uma descrição breve e clara do benefício.
```3. HTML gerado:
```html
<div class="flex flex-col items-center text-center">
<div class="w-12 h-12 rounded-xl bg-blue-100 ...">✨</div>
<div>
<h3 class="font-semibold text-lg mb-1">Recurso incrível</h3>
<p class="text-gray-600 text-sm">Uma descrição breve e clara do benefício.</p>
</div>
</div>
```Se você passar conteúdo sem um espaço reservado correspondente no template, um bloco vermelho aparece no HTML avisando o problema. Se um espaço obrigatório não for preenchido, aparece um bloco amarelo. Esses avisos são visíveis só no HTML gerado — intencionais para facilitar a identificação de erros.
Repetindo um slot com list=True
Às vezes você quer passar vários itens para um slot, e cada item deve receber o mesmo wrapper definido no template. Sem list=True, você teria que repetir o componente inteiro várias vezes. Com list=True, você passa uma lista separada por --- e o template cuida de duplicar o wrapper para cada item.
Exemplo: lista de badges
Digamos que o template de @tag renderiza cada modificador dentro de um @badge:
```seed
@div class=mt-3 flex flex-wrap gap-2
@badge variant=secondary
{modifiers}
```No .seed, passe os itens separados por --- com list=True:
```seed
@tag
@modifiers list=True
variant: muted, gradient
---
size: sm, lg
```Resultado: o @badge do template é duplicado — um para cada item separado por ---. Neste caso, dois badges.
Como funciona
A prop list=True no slot diz ao Seed para dividir o conteúdo em grupos usando --- como separador. Para cada grupo, o nó do template que contém o espaço reservado {modifiers} é clonado e renderizado com o conteúdo daquele grupo.
Sem list=True, o comportamento é o normal — todo o conteúdo vai para o slot de uma vez só. A funcionalidade é 100% retrocompatível.