Frameworks

Ícones no Svelte 5

O glyphfox/svelte traz um componente Svelte 5 para cada ícone, além de Icon, Fusion e MorphIcon, com as mesmas props de todos os outros pacotes do glyphfox.

Instalação

terminal
npm install glyphfox

Os componentes são arquivos-fonte .svelte que a sua aplicação compila, então o build precisa do Svelte 5 e do compilador dele, normalmente via vite-plugin-svelte, que todo projeto SvelteKit já tem. Eles são escritos com runes como $props e $state, por isso o Svelte 4 não consegue compilá-los.

O svelte 5 é uma peer dependency opcional do glyphfox: você só precisa dele quando importa glyphfox/svelte. O pacote expõe esse ponto de entrada sob a condição de export svelte, que o vite-plugin-svelte usa para reconhecer uma biblioteca Svelte e compilar os componentes dela para o navegador e para o servidor.

Use os componentes

Toolbar.svelte
<script>
  import { HomeIcon, SearchIcon, BellIcon } from 'glyphfox/svelte';

  let { unread = 0 } = $props();
</script>

<nav class="toolbar">
  <a href="/" aria-label="Home"><HomeIcon /></a>
  <SearchIcon size={20} weight={1.5} class="muted" />
  <BellIcon variant="duotone" secondaryColor="#ff7a1a" modifier={unread ? 'dot' : undefined} />
</nav>

Cada ícone é um componente com o nome do ícone em PascalCase e o sufixo Icon: arrow-right vira ArrowRightIcon, loader-circle vira LoaderCircleIcon. As props usam os nomes em camelCase, exatamente como no JavaScript, porque o Svelte passa as props para os componentes do jeito que foram escritas.

class e style são aplicados ao svg, e qualquer outro atributo, como aria-*, data-* ou id, é repassado a ele via spread. No Svelte 5, handlers de evento são props: onclick, onmouseenter e onmouseleave são repassados e continuam rodando quando o ícone tem um gatilho de click ou hover.

Os traços usam currentColor, então o ícone segue o color do CSS do elemento pai. A prop color define uma cor fixa no svg.

Peso, cantos e estilo

weight define o traço de 1 a 3, corners alterna entre junções redondas e retas, e variant escolhe outline, duotone ou solid. Abaixo de 24 px o traço fica um pouco mais grosso para que ícones pequenos mantenham presença; absoluteWeight mantém o valor exato.

Axes.svelte
<script>
  import { FolderIcon } from 'glyphfox/svelte';
</script>

<FolderIcon weight={1} />
<FolderIcon weight={3} corners="sharp" />
<FolderIcon variant="duotone" secondaryColor="#ff7a1a" />
<FolderIcon variant="solid" />
<FolderIcon size={16} weight={1.5} absoluteWeight />

Icon, modificadores e fusão

Icon renderiza qualquer spec da sintaxe de nomes: um nome, um selo modificador (file+check, com @tl, @tr, @bl ou @br para o canto), uma fusão (cloud&lock:overlap) ou um estilo (heart/solid). Fusion recebe uma lista de nomes e um layout: overlap, side, stack, grid, orbit, badge ou inside.

Os componentes de ícone trazem os próprios dados: cada um registra o seu ícone num bloco <script module>. Um nome dentro de uma string não tem nenhum import por trás, então registre esses nomes uma vez com registerIcons. Os selos modificadores são desenhados pelo motor e não precisam de registro.

src/lib/icons.js
import { registerIcons } from 'glyphfox/svelte';
import file from 'glyphfox/icons/file';
import cloud from 'glyphfox/icons/cloud';
import lock from 'glyphfox/icons/lock';
import menu from 'glyphfox/icons/menu';
import x from 'glyphfox/icons/x';
import play from 'glyphfox/icons/play';
import pause from 'glyphfox/icons/pause';

// Every name used in a string: Icon, Fusion, MorphIcon, morphStore and morphTo.
registerIcons([file, cloud, lock, menu, x, play, pause]);
FileStatus.svelte
<script>
  import './lib/icons.js';
  import { Icon, Fusion } from 'glyphfox/svelte';

  let { saved = false } = $props();
</script>

<Icon name={saved ? 'file+check' : 'file'} />
<Icon name="file+alert@tr" variant="duotone" />
<Fusion icons={['cloud', 'lock']} layout="overlap" gap={1} />

Importe o módulo de registro no seu arquivo de entrada ou no componente raiz. Um componente também pode registrar ícones no próprio bloco <script module>, que roda uma vez quando o módulo carrega, e não uma vez por instância.

MorphIcon, morphTo e morphStore

MorphIcon anima sempre que o name muda, o que combina naturalmente com $state:

MenuButton.svelte
<script>
  import { MorphIcon } from 'glyphfox/svelte';

  let open = $state(false);
</script>

<button type="button" aria-label="Menu" aria-expanded={open} onclick={() => (open = !open)}>
  <MorphIcon name={open ? 'x' : 'menu'} duration={300} />
</button>

Qualquer componente de ícone também aceita morphTo com um gatilho: click alterna a cada clique, hover acompanha o ponteiro, state acompanha active e o padrão, mount, faz o morph uma vez depois da montagem.

Triggers.svelte
<script>
  import { HeartIcon, PlayIcon } from 'glyphfox/svelte';

  let { playing = false } = $props();
</script>

<HeartIcon morphTo="heart/solid" trigger="click" />
<PlayIcon morphTo="pause" trigger="state" active={playing} />

morphStore(initial, options) é uma store para renderização própria. Chame set(name) para iniciar um morph e leia $store, um frame com icon e variant que você pode passar para Icon.

PlayToggle.svelte
<script>
  import './lib/icons.js';
  import { Icon, morphStore } from 'glyphfox/svelte';

  const frame = morphStore('play', { duration: 250 });
  let playing = $state(false);

  function toggle() {
    playing = !playing;
    frame.set(playing ? 'pause' : 'play');
  }
</script>

<button type="button" aria-label="Play" aria-pressed={playing} onclick={toggle}>
  {#if $frame}<Icon icon={$frame.icon} variant={$frame.variant} />{/if}
</button>

Pares ajustados à mão cobrem menu para x, play para pause, plus para check, sun para moon, eye para eye-off, bell para bell-ring, heart para heart/solid, copy para check, lock para unlock e wifi para wifi-off. Os outros pares se transformam com um pareamento automático.

Animações guiadas por estado

Os estados vivos são presets que entendem o ícone: draw desenha os traços na ordem do desenho, shake balança a partir do topo, e pop, wiggle, spin, pulse e bounce completam o conjunto. Com trigger="state", uma animação toca enquanto active for verdadeiro, então ela acompanha as suas runes diretamente.

Inbox.svelte
<script>
  import { BellIcon, LoaderCircleIcon, SparklesIcon } from 'glyphfox/svelte';

  let { hasNews = false, loading = false } = $props();
</script>

<BellIcon animate="shake" trigger="state" active={hasNews} />
{#if loading}<LoaderCircleIcon animate="spin" />{/if}
<SparklesIcon animate="draw" trigger="hover" />

Cada preset é uma pequena folha de estilo dentro do svg, então não precisa de import de CSS e é desativado para visitantes que preferem movimento reduzido. O guia de ícones animados cobre durações, atrasos e loops.

Imports profundos e tipos

O glyphfox/svelte reexporta todos os componentes, e os builds de produção descartam os que você não importa. Um import profundo resolve para um único arquivo .svelte, o que limita o código que o compilador e o servidor de desenvolvimento enxergam ao que você usa:

Logo.svelte
<script>
  import FoxIcon from 'glyphfox/svelte/icons/fox';
</script>

<FoxIcon size={32} variant="duotone" title="glyphfox" />

Os tipos vêm com o pacote. Todo componente é um Component<GlyphProps>, em que GlyphProps são as props compartilhadas mais qualquer atributo SVG, então um wrapper tipado pode repassar tudo:

AppIcon.svelte
<script lang="ts">
  import { Icon, type GlyphProps } from 'glyphfox/svelte';
  import type { IconName } from 'glyphfox';

  let { name, ...rest }: GlyphProps & { name: IconName } = $props();
</script>

<Icon {name} weight={1.75} {...rest} />

Nomes tipados como IconName são verificados em tempo de compilação, mas ainda precisam ser registrados para renderizar: veja as armadilhas abaixo e o guia de tree shaking.

Props

Todos os componentes de ícone, além de Icon, Fusion e MorphIcon, aceitam as props compartilhadas, em camelCase.

PropTipoPadrã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.

Icon acrescenta name, icon (dados de ícone) e gap. Fusion acrescenta icons, layout, gap, scale e offsets. MorphIcon acrescenta name e icon. O conteúdo filho é renderizado dentro do svg.

Armadilhas comuns

Props em kebab-case não fazem nada
No Svelte, secondary-color="#ff7a1a" não é a prop secondaryColor: ele é repassado ao svg como um atributo comum, e o ícone mantém o padrão. Use os nomes em camelCase em todo lugar.
Nomes que funcionam em desenvolvimento e somem em produção
Durante o desenvolvimento, o Vite faz o pre-bundle do pacote e todo nome é resolvido. Um build de produção mantém só o que você importa, e o Vite não inclui no bundle o carregador sob demanda que fica dentro de node_modules, então nomes não registrados em Icon, Fusion, MorphIcon, morphTo e morphStore renderizam um svg vazio. Registre esses nomes.
morphStore criada antes do registro
morphStore resolve um nome quando você chama set. Se o nome não estiver registrado nesse momento, ela fica esperando o carregador. Importe o módulo de registro antes de criar a store, como no exemplo acima.
Imports com asterisco e buscas dinâmicas
import * as icons from 'glyphfox/svelte' com icons[name] mantém todos os componentes no bundle. Monte um mapa com os componentes de que você precisa ou use Icon com nomes registrados.

Perguntas frequentes

Posso usar o glyphfox num projeto Svelte 4?

Não com glyphfox/svelte, que precisa do compilador do Svelte 5. Num app Svelte 4, o web component <glyph-fox> funciona com as mesmas props como atributos; veja o guia de web components.

Os componentes precisam do SvelteKit?

Não. Qualquer configuração de Svelte 5 que compile arquivos .svelte funciona, como o Vite puro com vite-plugin-svelte. O SvelteKit acrescenta renderização no servidor e pré-renderização, explicadas no guia de SvelteKit.

Ícones deste guia