Pular para o conteúdo

Componentes

Componentes Astro são os elementos básicos de qualquer projeto Astro. São componentes de template com apenas HTML sem execução no lado do cliente e que usam a extensão de arquivo .astro.

Componentes Astro são extremamente flexíveis. Um componente Astro pode ser tão pequeno quanto um trecho de HTML, como uma coleção de tags <meta> comuns que facilitam trabalhar com SEO. Componentes podem ser elementos de UI reutilizáveis, como um cabeçalho ou um cartão de perfil. Componentes Astro podem até mesmo conter o layout inteiro de uma página ou, quando estão na pasta especial src/pages/, ser uma página completa.

A coisa mais importante de entender sobre componentes Astro é que eles não renderizam no lado do cliente. Eles renderizam para HTML em tempo de build ou sob demanda. Você pode incluir código JavaScript dentro do frontmatter do seu componente, e todo esse código vai ser removido da página final enviada para o navegador dos seus usuários. O resultado é um site mais rápido, sem nenhum JavaScript adicionado por padrão.

Quando seu componente Astro precisar de interatividade no lado do cliente, você poderá adicionar tags <script> tradicionais do HTML (EN) ou componentes de um Framework de UI (EN) como “ilhas de cliente”.

Para componentes que precisam renderizar conteúdo personalizado ou dinâmico, você pode adiar a renderização no servidor adicionando uma diretiva do servidor (EN). Essas “ilhas de servidor” renderizarão seu conteúdo quando ele estiver disponível, sem atrasar o carregamento da página inteira.

Um componente Astro é feito de duas partes principais: o Script do Componente e o Template do Componente. Cada parte desempenha uma função diferente, mas juntas elas fornecem um framework fácil de usar e expressivo o bastante para lidar com tudo o que você quiser criar.

src/components/ComponenteVazio.astro
---
// Script do Componente (JavaScript)
---
<!-- Template do Componente (HTML + Expressões em JS) -->

Astro utiliza uma cerca de código (---) para identificar o script do seu componente Astro. Se você já escreveu Markdown antes, você já deve estar familiar com um conceito similar chamado frontmatter. A ideia do Astro de um script de componente foi diretamente inspirado por este conceito.

Você pode utilizar o script do componente para escrever qualquer código JavaScript necessário para renderizar o seu template. Isso pode incluir:

  • importar outros componentes Astro
  • importar componentes de outros frameworks, como React
  • importar dados, como um arquivo JSON
  • buscar conteúdo de uma API ou banco de dados
  • criar variáveis que você vai referenciar no seu template
src/components/MeuComponente.astro
---
import UmComponenteAstro from '../components/UmComponenteAstro.astro';
import UmComponenteReact from '../components/UmComponenteReact.jsx';
import algunsDados from '../dados/pokemon.json';
// Acesse props passadas ao componente, como `<X titulo="Olá, Mundo!" />`
const { titulo } = Astro.props;
// Busque dados externos, até mesmo de uma API privada ou banco de dados
const dados = await fetch('ALGUMA_URL_SECRETA_API/usuarios').then(r => r.json());
---
<!-- Seu template está aqui! -->

A cerca de código é projetada para garantir que o JavaScript que você escreve nela está “cercado”. Ele não irá escapar para a sua aplicação frontend ou cair nas mãos dos seus usuários. Você pode com segurança escrever aqui código que é custoso ou sensível (como uma chamada ao seu banco de dados privado) sem se preocupar com ele indo parar no navegador do seu usuário em algum momento.

O template do componente está abaixo da cerca do código e determina o HTML que será produzido pelo seu componente.

Se você escrever HTML puro aqui, o seu componente irá renderizar esse HTML em qualquer página Astro em que ele é importado e utilizado.

Porém, a sintaxe do template de componentes Astro também suporta expressões JavaScript, tags <style> (EN) e <script> (EN) do Astro, componentes importados e diretivas especiais do Astro (EN). Dados e valores definidos no script do componente podem ser utilizados no template do componente para produzir HTML criado dinamicamente.

src/components/MeuPokemonFavorito.astro
---
// O script do seu componente está aqui!
import Banner from '../components/Banner.astro';
import Avatar from '../components/Avatar.astro';
import ComponentePokemonReact from '../components/ComponentePokemonReact.jsx';
const meuPokemonFavorito = [/* ... */];
const { titulo } = Astro.props;
---
<!-- comentários HTML são suportados! -->
{/* sintaxe de comentário do JS também é válida! */}
<Banner />
<h1>Olá, mundo!</h1>
<!-- Use props e outras variáveis do script do componente: -->
<p>{titulo}</p>
<!-- Adie a renderização do componente e forneça um conteúdo alternativo durante o carregamento: -->
<Avatar server:defer>
<svg slot="fallback" class="avatar-generico" transition:name="avatar">...</svg>
</Avatar>
<!-- Inclua outros componentes de frameworks de UI com a diretiva `client:` para hidratá-los: -->
<ComponentePokemonReact client:visible />
<!-- Misture HTML com expressões JavaScript, similar ao JSX: -->
<ul>
{meuPokemonFavorito.map((dados) => <li>{dados.nome}</li>)}
</ul>
<!-- Use uma diretiva de template para construir nomes de classe a partir de múltiplas strings ou até mesmo objetos! -->
<p class:list={["adicione", "dinâmicos", { classNames: true }]} />

Componentes são projetados para serem reutilizáveis e combináveis. Você pode utilizar componentes dentro de outros componentes para criar UIs cada vez mais avançadas. Por exemplo, um componente Botao pode ser utilizado para criar um componente GrupoBotoes:

src/components/GrupoBotoes.astro
---
import Botao from './Botao.astro';
---
<div>
<Botao titulo="Botão 1" />
<Botao titulo="Botão 2" />
<Botao titulo="Botão 3" />
</div>

Um componente Astro pode definir e aceitar props. Essas props então se tornam disponíveis ao template do componente para renderizar HTML. Props estão disponíveis na global Astro.props no script do frontmatter.

Aqui está um exemplo de um componente que recebe uma prop saudacao e uma prop nome. Note que as props a serem recebidas são desconstruídas a partir do objeto global Astro.props.

src/components/TituloSaudacao.astro
---
// Uso: <TituloSaudacao saudacao="Salve" nome="Parceiro" />
const { saudacao, nome } = Astro.props;
---
<h2>{saudacao}, {nome}!</h2>

Este componente, quando importado e renderizado em outros componentes Astro, layouts ou páginas, pode passar essas props como atributos:

src/components/CartaoSaudacoes.astro
---
import TituloSaudacao from './TituloSaudacao.astro';
const nome = 'Astro';
---
<h1>Cartão de Saudações</h1>
<TituloSaudacao saudacao="Oi" nome={nome} />
<p>Espero que você tenha um dia maravilhoso!</p>

Você também pode definir suas props com TypeScript através de uma interface de tipo Props. Astro vai automaticamente pegar qualquer interface Props definida no frontmatter e dar avisos/erros de tipagem para o seu projeto. Estas props também podem definir valores padrão quando desconstruídas de Astro.props.

src/components/TituloSaudacao.astro
---
export interface Props {
nome: string;
saudacao?: string;
}
const { saudacao = "Olá", nome } = Astro.props;
---
<h2>{saudacao}, {nome}!</h2>

Props do componente podem receber valores padrão para serem utilizados quando nenhum é fornecido.

src/components/TituloSaudacao.astro
---
const { saudacao = "Olá", nome = "Astronauta" } = Astro.props;
---
<p>{saudacao}, {nome}!</p>

O elemento <slot /> é um placeholder para conteúdo HTML externo, permitindo que você injete (ou “encaixe”) elementos filhos de outros arquivos no template do seu componente.

Por padrão, todos os elementos filhos passados para o componente serão renderizados em seu <slot />.

src/components/Involucro.astro
---
import Cabecalho from './Cabecalho.astro';
import Logo from './Logo.astro';
import Rodape from './Rodape.astro';
const { titulo } = Astro.props;
---
<div id="invólucro-do-conteúdo">
<Cabecalho />
<Logo />
<h1>{titulo}</h1>
<slot /> <!-- filhos virão para cá -->
<Rodape />
</div>
src/pages/fred.astro
---
import Involucro from '../components/Involucro.astro';
---
<Involucro titulo="Página do Fred">
<h2>Tudo sobre Fred</h2>
<p>Aqui estão algumas coisas sobre Fred.</p>
</Involucro>

Este padrão é a base de um componente de layout Astro: uma página inteira de conteúdo HTML pode ser “envolvida” com tags <AlgumComponenteDeLayout></AlgumComponenteDeLayout> e enviada ao componente para ser renderizada dentro dos elementos comuns de página definidos nele.

Consulte as funções utilitárias de Astro.slots para conhecer outras maneiras de acessar e renderizar o conteúdo de slots.

Um componente Astro também pode ter slots nomeados. Isso permite que você passe apenas elementos HTML com o nome de slot correspondente para a localização do slot.

Slots são nomeados usando o atributo name:

src/components/Involucro.astro
---
import Cabecalho from './Cabecalho.astro';
import Logo from './Logo.astro';
import Rodape from './Rodape.astro';
const { titulo } = Astro.props;
---
<div id="invólucro-do-conteúdo">
<Cabecalho />
<!-- filhos com o atributo `slot="depois-do-cabecalho"` virão para cá -->
<slot name="depois-do-cabecalho" />
<Logo />
<h1>{titulo}</h1>
<!-- filhos sem um atributo `slot`, ou com `slot="default"`, virão para cá -->
<slot />
<Rodape />
<!-- filhos com o atributo `slot="depois-do-rodape"` virão para cá -->
<slot name="depois-do-rodape" />
</div>

Para injetar conteúdo HTML dentro de um slot em particular, use o atributo slot em qualquer elemento filho para especificar o nome do slot. Todos os outros elementos filhos do componente serão injetados no <slot /> padrão (não nomeado).

src/pages/fred.astro
---
import Involucro from '../components/Involucro.astro';
---
<Involucro titulo="Página do Fred">
<img src="https://minha.foto/fred.jpg" slot="depois-do-cabecalho" />
<h2>Tudo sobre Fred</h2>
<p>Aqui estão algumas coisas sobre Fred.</p>
<p slot="depois-do-rodape">Copyright 2022</p>
</Involucro>

Para passar múltiplos elementos HTML para o placeholder <slot /> de um componente sem ter uma <div> envolta, use o atributo slot="" no componente <Fragment /> do Astro:

src/components/TabelaCustomizada.astro
---
// Cria uma tabela customizada com slots nomeados para o conteúdo do cabeçalho e do corpo
---
<table class="bg-white">
<thead class="sticky top-0 bg-white"><slot name="cabecalho" /></thead>
<tbody class="[&_tr:nth-child(odd)]:bg-gray-100"><slot name="corpo" /></tbody>
</table>

Injete múltiplas linhas e colunas de conteúdo HTML usando o atributo slot="" para especificar o conteúdo do "cabecalho" e "corpo". Elementos individuais do HTML também podem ser estilizados:

src/components/TabelaDeEstoque.astro
---
import TabelaCustomizada from './TabelaCustomizada.astro';
---
<TabelaCustomizada>
<Fragment slot="cabecalho"> <!-- passar cabeçalho da tabela -->
<tr><th>Nome do Produto</th><th>Quantidade no estoque</th></tr>
</Fragment>
<Fragment slot="corpo"> <!-- passar corpo da tabela -->
<tr><td>Chinelos</td><td>64</td></tr>
<tr><td>Botas</td><td>32</td></tr>
<tr><td>Tênis</td><td class="text-red-500">0</td></tr>
</Fragment>
</TabelaCustomizada>

Note que slots nomeados precisam ser um filho imediato do componente. Você não pode passar slots nomeados através de elementos aninhados.

Slots também podem renderizar conteúdo de fallback. Quando nenhum filho correspondente for passado a um slot, um elemento <slot /> irá renderizar seus próprios filhos como conteúdo substituto.

src/components/Involucro.astro
---
import Cabecalho from './Cabecalho.astro';
import Logo from './Logo.astro';
import Rodape from './Rodape.astro';
const { titulo } = Astro.props;
---
<div id="invólucro-do-conteúdo">
<Cabecalho />
<Logo />
<h1>{titulo}</h1>
<slot>
<p>Esse é o meu conteúdo de fallback se nenhum filho for passado ao slot</p>
</slot>
<Rodape />
</div>

Conteúdo de fallback só será mostrado quando não houver elementos correspondentes com o atributo slot="nome" sendo passados para um slot nomeado.

Astro vai passar um slot vazio quando um elemento de slot existir, mas não tiver nenhum conteúdo para passar. Conteúdo de fallback não pode ser utilizado como um padrão no caso de um slot vazio ser passado. Conteúdo de fallback só é exibido quando nenhum elemento de slot é encontrado.

Slots podem ser transferidos para outros componentes. Por exemplo, quando criando layouts aninhados:

src/layouts/BaseLayout.astro
---
---
<html lang="pt-BR">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<slot name="cabecalho" />
</head>
<body>
<slot />
</body>
</html>
src/layouts/LayoutInicio.astro
---
import LayoutBase from './LayoutBase.astro';
---
<LayoutBase>
<slot name="cabecalho" slot="cabecalho" />
<slot />
</LayoutBase>

Agora, os slots padrão e cabecalho passados para LayoutInicio vão ser transferidos para o pai LayoutBase.

src/pages/index.astro
---
import LayoutInicio from '../layouts/LayoutInicio.astro';
---
<LayoutInicio>
<title slot="cabecalho">Astro</title>
<h1>Astro</h1>
</LayoutInicio>

Astro suporta a importação e uso de arquivos .html como componentes ou colocando esses arquivos no subdiretório src/pages/ como páginas. Você pode querer utilizar componentes HTML se você estiver reutilizando código de um site já construído sem um framework ou se você quer se certificar de que seu componente não tem funcionalidades dinâmicas.

Componentes HTML devem conter apenas HTML válido, e portanto não tem as funcionalidades principais de componentes Astro:

Leia mais sobre como utilizar componentes de frameworks de UI (EN) em seu projeto Astro.
Contribua Comunidade Patrocine