Ícones no Astro
O Astro renderiza componentes em HTML no servidor ou durante o build, o que combina com ícones SVG: chame o renderizador no frontmatter e a página recebe SVG inline puro, sem JavaScript no cliente. As ilhas e o custom element cuidam dos ícones que precisam reagir.
Instalação
Instale o pacote. Ícones estáticos não precisam de nenhuma integração do Astro, porque o glyphfox é feito de módulos ES puros que rodam no frontmatter. Ilhas criadas com glyphfox/react, glyphfox/vue ou glyphfox/svelte precisam da integração do Astro correspondente.
npm install glyphfox # only for islands npx astro add react
Ícones no frontmatter
O código do frontmatter roda no servidor, ou durante o build no caso de páginas estáticas. O toSvg retorna a string SVG de qualquer nome de ícone, e o set:html a escreve na página sem escapá-la:
--- import { toSvg } from 'glyphfox'; const search = toSvg('search', { size: 20 }); --- <label class="search"> <Fragment set:html={search} /> <input type="search" name="q" aria-label="Search the docs" /> </label>
O toSvg aceita a sintaxe de nomes completa, então selos, fusões e estilos cabem em uma única string: toSvg('file+check@tr'), toSvg('cloud&lock:overlap'), toSvg('heart/solid').
Importar glyphfox carrega todos os ícones, mas só no servidor ou no build. Nada disso chega ao navegador, porque o frontmatter nunca roda lá.
Um componente Icon.astro
Coloque a chamada dentro de um componente para que as páginas passem props em vez de opções. O SVG vai direto para o elemento pai, sem um elemento wrapper:
--- import { toSvg, type SvgOptions } from 'glyphfox'; interface Props extends SvgOptions { name: string; } const { name, ...options } = Astro.props; const svg = toSvg(name, options); --- <Fragment set:html={svg} />
--- import Icon from './Icon.astro'; --- <nav class="nav"> <a href="/"><Icon name="home" size={20} /> Home</a> <a href="/docs/"><Icon name="book-open" size={20} weight={1.5} /> Docs</a> <a href="/new/"><Icon name="file+plus" size={20} title="New file" /></a> </nav> <style> .nav :global(.glyphfox) { color: #6b7280; } .nav a:hover :global(.glyphfox) { color: #111827; } </style>
Todo svg traz as classes glyphfox e glyphfox-NAME. A marcação inserida com set:html não recebe os atributos que o Astro usa para aplicar escopo aos estilos do componente, então selecione-a com :global() dentro de um seletor pai com escopo, como acima, ou deixe que ela herde color por meio de currentColor.
O link de ícone acima não tem texto, então o ícone dele recebe um title: isso adiciona role="img", aria-label e um <title>, e o link obtém o nome a partir dele. Ícones ao lado de texto visível continuam decorativos. Há mais padrões no guia de acessibilidade.
Movimento sem JavaScript
O SVG pode levar o próprio CSS, então estados vivos e morphs no hover funcionam em HTML estático, sem script: animate com o padrão trigger="mount" ou com "hover", e morphTo com trigger="hover", que reage ao svg e ao pai direto dele.
--- import Icon from './Icon.astro'; --- <a class="next" href="/chapter-2/"> Next chapter <Icon name="arrow-right" morphTo="chevron-right" trigger="hover" /> </a> <p class="status"> <Icon name="loader" animate="spin" title="Building" /> Building the preview </p>
Como o Icon.astro não adiciona wrapper, o svg é filho direto do link, e passar o mouse em qualquer ponto do link faz a seta se transformar. Todos os presets param com prefers-reduced-motion; os presets e os gatilhos estão listados em ícones animados.
Ilhas para estado
Ícones que acompanham um estado, como um botão de menu que se transforma em um ícone de fechar, ficam em uma ilha. Use o pacote do framework da ilha e hidrate-a com uma diretiva client:
import { useState } from 'react'; import { MorphIcon, registerIcons } from 'glyphfox/react'; import menu from 'glyphfox/icons/menu'; import x from 'glyphfox/icons/x'; // Names passed to MorphIcon load on demand; registering them // puts the icon in the server rendered HTML. registerIcons([menu, x]); export default function MenuButton() { const [open, setOpen] = useState(false); return ( <button type="button" aria-expanded={open} aria-label={open ? 'Close menu' : 'Open menu'} onClick={() => setOpen(!open)} > <MorphIcon name={open ? 'x' : 'menu'} duration={300} /> </button> ); }
--- import MenuButton from '../components/MenuButton.jsx'; --- <header> <MenuButton client:load /> </header>
O Astro renderiza as ilhas primeiro no servidor. Componentes de ícone como MenuIcon registram o próprio ícone quando o seu código os usa, mas nomes passados para MorphIcon, Icon ou morphTo são carregados sob demanda, então, sem registerIcons, o HTML do servidor fica com um svg vazio até a ilha ser hidratada.
O mesmo vale para glyphfox/vue e para glyphfox/svelte, que precisa do Svelte 5. Para ilhas abaixo da dobra, client:visible ou client:idle adia o download até ele ser necessário. Os detalhes de cada framework estão nos guias do React, do Vue e do Svelte.
O custom element
Sem framework, o elemento <glyph-fox> cuida de cliques, hover e trocas de nome. O Astro processa e empacota as tags <script> dos componentes e inclui cada script uma vez por página, mesmo quando o componente aparece várias vezes:
<button type="button" class="like" aria-pressed="false" aria-label="Like"> <glyph-fox name="heart" morph-to="heart/solid" trigger="state"></glyph-fox> </button> <script> import { defineGlyphFox } from 'glyphfox/web/element'; import { registerIcons } from 'glyphfox/core'; import heart from 'glyphfox/icons/heart'; registerIcons([heart]); defineGlyphFox(); for (const button of document.querySelectorAll('button.like')) { const icon = button.querySelector('glyph-fox'); button.addEventListener('click', () => { const on = button.getAttribute('aria-pressed') !== 'true'; button.setAttribute('aria-pressed', String(on)); icon.toggleAttribute('active', on); }); } </script>
O botão controla o ícone por meio de trigger="state" e do atributo active. Com trigger="click", o elemento escutaria os eventos nele mesmo, e um clique no padding do botão alternaria aria-pressed sem fazer o ícone se transformar.
Os custom elements continuam definidos durante a navegação no cliente com o roteador de view transitions do Astro, então os ícones das páginas novas fazem o upgrade sozinhos. Código que adiciona listeners, como o loop acima, roda uma vez só; com o roteador, rode-o de novo no evento astro:page-load.
Classes do Tailwind
Com o Tailwind CSS no projeto, o plugin do glyphfox desenha os ícones como máscaras CSS, outra opção sem JavaScript, prática em templates com muito conteúdo. A configuração e a sintaxe das classes estão no guia do Tailwind.
<h1 class="flex items-center gap-3"> <span class="gf-rocket text-4xl text-orange-500" aria-hidden="true"></span> Launch faster </h1>
Props
O Icon.astro repassa as props para o toSvg, então aceita as opções compartilhadas com os nomes em camelCase, além de class e style como strings para o svg. Diferente do renderizador do core, aqui morphTo pode ser um nome, porque o toSvg o resolve.
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
size | number, string | 24 | Largura e altura; números são pixels. |
color | string | currentColor | Cor principal. |
secondaryColor | string | color | Cor da camada duotone e do preenchimento sólido. |
secondaryOpacity | number | 0.3 / 1 | Opacidade da camada duotone ou do preenchimento sólido. |
weight | number | 2 | Traço de 1 a 3 na grade de 24, com compensação óptica abaixo de 24 px. |
absoluteWeight | boolean | false | Mantém o traço com weight pixels em qualquer tamanho. |
corners | round, sharp | round | Junções e pontas redondas ou retas. |
variant | outline, duotone, solid | outline | Eixo de estilo; o sólido vem das formas fechadas. |
rotate | number | 0 | Rotação em graus. |
flipX | boolean | false | Espelha na horizontal. |
flipY | boolean | false | Espelha na vertical. |
mirrorRtl | boolean | false | Espelha em layouts da direita para a esquerda. |
animate | draw, pop, wiggle, spin, pulse, bounce, shake | nenhum | Animação de estado vivo. |
trigger | mount, hover, click, state | mount | Quando a animação ou o morph acontece. |
active | boolean | false | O estado para o gatilho state. |
duration | number (ms) | por animação | Duração da animação ou do morph. |
delay | number (ms) | 0 | Atraso da animação ou do morph. |
loop | boolean, number | false | Repete para sempre ou um número de vezes (spin e pulse repetem por padrão). |
modifier | plus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dot | nenhum | Selo com espaço de recorte automático. |
modifierCorner | top-left, top-right, bottom-left, bottom-right | bottom-right | Canto do selo. |
morphTo | name, data | nenhum | Destino do morph; o gatilho decide quando aparece. |
title | string | nenhum | Nome acessível: title, role img e aria-label. |
decorative | boolean | true sem title | Esconde o ícone das tecnologias assistivas. |
Armadilhas comuns
- Estilos com escopo e set:html
- As regras do bloco de estilo de um componente não se aplicam à marcação inserida com
set:html, porque faltam nela os atributos de escopo. Use:global(.glyphfox)dentro de um seletor com escopo ou herdecolor. - Nomes em ilhas
MorphIcon,IconemorphTocarregam os nomes sob demanda. Registre os dados deles comregisterIconspara que o HTML do servidor venha completo.- Gatilhos de clique dentro de botões
trigger="click"noglyph-foxescuta os cliques no próprio ícone, e cliques no padding do botão não chegam até ele. Usetrigger="state"e definaactivea partir do botão.- Nomes desconhecidos interrompem o build
- O
toSvglança um erro para um nome que não existe, o que faz um build estático falhar e devolve um erro no modo servidor. Confira os nomes vindos do conteúdo com a lista de ícones ou capture o erro quando eles vierem de dados do usuário. - Bundles de servidor em runtimes de edge
- O
toSvgdo ponto de entrada principal coloca todos os ícones no bundle do servidor, cerca de 154 KB minificados. Onde o tamanho da função é limitado, userenderToStringdeglyphfox/corecom imports por ícone e passe dados de ícone paramorphTo. - Wrappers e morphs no hover
- Um morph no hover reage ao svg e ao pai direto dele. Envolver o ícone em um elemento extra torna esse elemento o pai, então passar o mouse sobre o link em volta dele não inicia mais o morph.
Perguntas frequentes
Ícones renderizados no frontmatter enviam algum JavaScript?
Não. O frontmatter roda no servidor ou durante o build, e a página recebe SVG puro. Presets e morphs no hover são CSS dentro desse SVG. Só as ilhas e o custom element adicionam código no cliente.
Posso usar ícones em conteúdo Markdown ou MDX?
No MDX, importe o Icon.astro e use-o como em qualquer componente. Markdown puro não consegue importar componentes, então renderize os ícones no layout em volta do conteúdo ou use as classes do Tailwind em HTML bruto onde o seu Markdown permitir.