Frameworks

Í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.

terminal
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:

src/pages/index.astro
---
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:

src/components/Icon.astro
---
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} />
src/components/Nav.astro
---
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.

src/components/Chapter.astro
---
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:

src/components/MenuButton.jsx
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>
  );
}
src/layouts/Base.astro
---
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:

src/components/LikeButton.astro
<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.

src/components/Hero.astro
<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çãoTipoPadrãoDescrição
sizenumber, string24Largura e altura; números são pixels.
colorstringcurrentColorCor principal.
secondaryColorstringcolorCor da camada duotone e do preenchimento sólido.
secondaryOpacitynumber0.3 / 1Opacidade da camada duotone ou do preenchimento sólido.
weightnumber2Traço de 1 a 3 na grade de 24, com compensação óptica abaixo de 24 px.
absoluteWeightbooleanfalseMantém o traço com weight pixels em qualquer tamanho.
cornersround, sharproundJunções e pontas redondas ou retas.
variantoutline, duotone, solidoutlineEixo de estilo; o sólido vem das formas fechadas.
rotatenumber0Rotação em graus.
flipXbooleanfalseEspelha na horizontal.
flipYbooleanfalseEspelha na vertical.
mirrorRtlbooleanfalseEspelha em layouts da direita para a esquerda.
animatedraw, pop, wiggle, spin, pulse, bounce, shakenenhumAnimação de estado vivo.
triggermount, hover, click, statemountQuando a animação ou o morph acontece.
activebooleanfalseO estado para o gatilho state.
durationnumber (ms)por animaçãoDuração da animação ou do morph.
delaynumber (ms)0Atraso da animação ou do morph.
loopboolean, numberfalseRepete para sempre ou um número de vezes (spin e pulse repetem por padrão).
modifierplus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dotnenhumSelo com espaço de recorte automático.
modifierCornertop-left, top-right, bottom-left, bottom-rightbottom-rightCanto do selo.
morphToname, datanenhumDestino do morph; o gatilho decide quando aparece.
titlestringnenhumNome acessível: title, role img e aria-label.
decorativebooleantrue sem titleEsconde 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 herde color.
Nomes em ilhas
MorphIcon, Icon e morphTo carregam os nomes sob demanda. Registre os dados deles com registerIcons para que o HTML do servidor venha completo.
Gatilhos de clique dentro de botões
trigger="click" no glyph-fox escuta os cliques no próprio ícone, e cliques no padding do botão não chegam até ele. Use trigger="state" e defina active a partir do botão.
Nomes desconhecidos interrompem o build
O toSvg lanç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 toSvg do ponto de entrada principal coloca todos os ícones no bundle do servidor, cerca de 154 KB minificados. Onde o tamanho da função é limitado, use renderToString de glyphfox/core com imports por ícone e passe dados de ícone para morphTo.
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.

Ícones deste guia