Frameworks

Ícones no SolidJS

Ainda não existe um pacote dedicado ao Solid, e ele não faz falta. O elemento <glyph-fox> funciona em templates do Solid, e um componente de poucas linhas sobre o glyphfox/core oferece ícones reativos, compatíveis com tree shaking, que renderizam no servidor.

Instalação

Instale o pacote principal. Tudo nesta página usa pontos de entrada que já vêm nele: glyphfox/web para o elemento, e glyphfox/core com glyphfox/icons/NAME para o componente.

terminal
npm install glyphfox
AspectoElemento glyph-foxComponente Glyph
RenderizaNo navegador, quando o elemento faz o upgrade.No servidor e no navegador.
EnviaO elemento, o motor dele e os ícones que você registra.O renderizador e os módulos de ícone que você importa.
MovimentoMorph a cada troca de nome, gatilhos de hover e de clique, estados.Movimento em CSS dentro do SVG: presets e morphs no hover.
Ideal paraÍcones que reagem ao usuário.A maioria dos ícones de um app.

O elemento glyph-fox

Registre o elemento uma vez, no seu arquivo de entrada. O glyphfox/web registra todos os ícones; para deixar no bundle só os ícones que você listar, use glyphfox/web/element com registerIcons, como mostra o guia de web components.

src/index.jsx
import { render } from 'solid-js/web';
import 'glyphfox/web';
import App from './App';

render(() => <App />, document.getElementById('root'));

Atributos estáticos são compilados no template, então chegam ao elemento como atributos e funcionam do jeito que estão escritos:

Toolbar.jsx
export function Toolbar() {
  return (
    <div class="toolbar">
      <glyph-fox name="settings" size="20" weight="1.5" />
      <glyph-fox name="bell" animate="shake" trigger="hover" />
    </div>
  );
}

Com valores dinâmicos é diferente. Em custom elements, o Solid atribui expressões como propriedades, e o <glyph-fox> não tem propriedades: ele lê atributos. Coloque o namespace attr: antes das props dinâmicas para que o Solid defina o atributo em vez da propriedade.

MenuButton.jsx
import { createSignal } from 'solid-js';

export function MenuButton() {
  const [open, setOpen] = createSignal(false);
  return (
    <button
      type="button"
      aria-expanded={open()}
      aria-label={open() ? 'Close menu' : 'Open menu'}
      onClick={() => setOpen(!open())}
    >
      <glyph-fox attr:name={open() ? 'x' : 'menu'} morph duration="300" />
    </button>
  );
}

O atributo morph faz o elemento animar toda troca de name, então cada alternância do signal toca o morph de menu para fechar, ajustado à mão. Eventos não precisam de nada especial: onClick em um elemento pai funciona normalmente, e gatilhos como trigger="click" são tratados dentro do elemento.

TypeScript

Os tipos JSX do Solid não conhecem o glyph-fox. Declare-o uma vez em um arquivo de declaração e liste os atributos que você define via attr: em ExplicitAttributes, a interface que o Solid lê para esse namespace.

src/glyphfox.d.ts
import 'solid-js';

type GlyphFoxAttributes = {
  name?: string;
  size?: string | number;
  color?: string;
  weight?: string | number;
  variant?: 'outline' | 'duotone' | 'solid';
  animate?: 'draw' | 'pop' | 'wiggle' | 'spin' | 'pulse' | 'bounce' | 'shake';
  trigger?: 'mount' | 'hover' | 'click' | 'state';
  morph?: boolean | string;
  'morph-to'?: string;
  duration?: string | number;
};

declare module 'solid-js' {
  namespace JSX {
    interface IntrinsicElements {
      'glyph-fox': JSX.HTMLAttributes<HTMLElement> & GlyphFoxAttributes;
    }
    interface ExplicitAttributes {
      name: string;
      size: string | number;
      active: boolean | string;
    }
  }
}

Um pequeno componente Glyph

Para ícones que não precisam da interação embutida no elemento, renderize o SVG você mesmo. O renderToString de glyphfox/core transforma dados de ícone em marcação com todas as props compartilhadas, e cada módulo glyphfox/icons/NAME guarda os dados de um ícone, então o bundle leva só o que você importa.

Glyph.jsx
import { splitProps } from 'solid-js';
import { renderToString } from 'glyphfox/core';

export function Glyph(props) {
  const [local, options] = splitProps(props, ['icon', 'class']);
  return (
    <span
      class={local.class}
      style={{ display: 'inline-flex', 'line-height': '0' }}
      innerHTML={renderToString(local.icon, options)}
    />
  );
}
Nav.jsx
import { Glyph } from './Glyph';
import home from 'glyphfox/icons/home';
import bell from 'glyphfox/icons/bell';

export function Nav(props) {
  return (
    <nav>
      <a href="/">
        <Glyph icon={home} size={20} /> Home
      </a>
      <button type="button" aria-label="Notifications">
        <Glyph icon={bell} animate="shake" trigger="state" active={props.unread > 0} />
      </button>
    </nav>
  );
}

O efeito por trás de innerHTML rastreia todas as props que o renderToString lê, então uma mudança em active, size ou icon reescreve a marcação. A marcação é substituída, não interpolada. Para um morph entre dois ícones, use o elemento ou um morph CSS no hover com morphTo:

NextLink.jsx
import { Glyph } from './Glyph';
import arrowRight from 'glyphfox/icons/arrow-right';
import chevronRight from 'glyphfox/icons/chevron-right';

export const NextLink = () => (
  <a href="/next" class="next">
    Next <Glyph icon={arrowRight} morphTo={chevronRight} trigger="hover" />
  </a>
);

Com glyphfox/core, morphTo recebe dados de ícone, não um nome: só o toSvg do ponto de entrada principal resolve nomes. Um nome passado aqui é ignorado, e o ícone fica parado. O morph CSS acontece enquanto o ponteiro está sobre o svg ou sobre o pai direto dele, que neste componente é o span que o envolve.

A sintaxe de nomes (file+check@tr, cloud&lock) também é resolvida pelo toSvg. Com o core, use no lugar dela as props e os helpers correspondentes: modifier e modifierCorner para selos, fuse para fusões.

Status.jsx
import { fuse } from 'glyphfox/core';
import { Glyph } from './Glyph';
import file from 'glyphfox/icons/file';
import cloud from 'glyphfox/icons/cloud';
import lock from 'glyphfox/icons/lock';

const secureCloud = fuse([cloud, lock], { layout: 'overlap' });

export const Status = () => (
  <p>
    <Glyph icon={file} modifier="check" modifierCorner="top-right" title="Saved" />
    <Glyph icon={secureCloud} size={32} title="Encrypted backup" />
  </p>
);

SolidStart e renderização no servidor

O componente Glyph renderiza no servidor como qualquer outra marcação: o SolidStart escreve o SVG no HTML, então os ícones fazem parte da primeira pintura e o layout não se mexe quando a página é hidratada.

O elemento é um recurso do navegador. Ele faz o upgrade depois que o script dele roda e não usa shadow DOM declarativo, então o HTML do servidor contém a tag vazia. Reserve o espaço dele com CSS ou deixe no componente Glyph os ícones que precisam aparecer de imediato. Os prós e contras de cada framework estão em renderização no servidor.

src/app.css
glyph-fox:not(:defined) {
  display: inline-block;
  width: 24px;
  height: 24px;
}

Importar glyphfox/web no servidor não causa problema: o elemento verifica se customElements existe e não faz nada sem ele. Mesmo assim, importe-o a partir de código do cliente, como src/entry-client.tsx no SolidStart, para que o elemento e os ícones dele fiquem fora do bundle do servidor.

Props

O componente Glyph repassa as props para o renderToString, então aceita as opções compartilhadas com os nomes em camelCase. No elemento, as mesmas props são atributos em kebab-case, listados no guia de web components.

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

Props dinâmicas sem attr:
name={...} no glyph-fox define uma propriedade que o elemento ignora, e o ícone renderiza vazio. Escreva attr:name={...}. Strings estáticas funcionam sem o prefixo.
Um nome em morphTo
O renderToString do core precisa de dados de ícone em morphTo. Uma string é ignorada. Importe o ícone de destino e passe os dados dele.
Animações de montagem tocam de novo
Cada mudança de prop substitui o innerHTML, então um preset com o padrão trigger="mount" toca de novo. Para animações ligadas a um estado, use trigger="state" com active.
Todos os ícones sem querer
import { toSvg } from 'glyphfox' traz todos os ícones para o bundle, porque um nome pode apontar para qualquer um deles. Em código do cliente, use o core com um módulo por ícone; deixe o toSvg para código só de servidor.
O elemento no servidor
O HTML do servidor fica com um <glyph-fox> vazio até o script rodar. Reserve o tamanho dele ou renderize com o componente Glyph os ícones que precisam estar visíveis no HTML do servidor.
O span que envolve o svg
O componente Glyph envolve o svg em um span: o gap de flex e de grid se aplica ao span, e class vai para o span, não para o svg. Defina tamanhos pelas props em vez de usar CSS no span.

Perguntas frequentes

Existe um pacote glyphfox para Solid?

Ainda não. As duas abordagens desta página usam o que o pacote glyphfox já traz hoje: o custom element e o renderizador do core, que é a base dos pacotes de React, Vue e Svelte.

Os ícones se atualizam quando um signal muda?

Sim. Com o elemento, faça o binding via attr: e o elemento se redesenha a cada mudança de atributo, com morph quando o atributo morph está definido. Com o componente Glyph, o efeito por trás de innerHTML rastreia as props que o renderizador lê e reescreve a marcação.

Ícones deste guia