Iconos en Angular
glyphfox-angular agrega un componente standalone gf-icon y un proveedor que registra iconos por nombre. Es compatible con Angular 17 y versiones posteriores, con el renderizado en el servidor y con la detección de cambios OnPush y zoneless.
Instalación
npm install glyphfox glyphfox-angular
glyphfox-angular se publica con el formato de paquete de Angular, se compila con ng-packagr y usa glyphfox para los datos de los iconos y el motor de renderizado. Su peer dependency es @angular/core 17 o posterior, porque los inputs dependen de transformaciones de input como booleanAttribute.
Registra iconos con provideGlyphFox
gf-icon busca los iconos por nombre, así que registra los que usan tus plantillas. Cada icono es una exportación de datos con nombre de glyphfox: home es iconHome y arrow-right es iconArrowRight.
import { ApplicationConfig } from '@angular/core'; import { provideRouter } from '@angular/router'; import { iconCheck, iconFile, iconHome, iconMenu, iconSave, iconSearch, iconX } from 'glyphfox'; import { provideGlyphFox } from 'glyphfox-angular'; import { routes } from './app.routes'; export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), provideGlyphFox({ icons: [iconHome, iconSearch, iconFile, iconMenu, iconX, iconSave, iconCheck], defaults: { weight: 1.75 }, }), ], };
defaults se aplica a todos los gf-icon que hay bajo ese inyector, y un input en el elemento tiene prioridad sobre el valor predeterminado. Varias llamadas a provideGlyphFox en el mismo inyector se suman: se registran todos sus iconos y sus valores predeterminados se combinan en orden. provideGlyphFoxIcons(icons) es la forma abreviada cuando solo registras iconos.
Para que todos los iconos estén disponibles por nombre, pasa el objeto completo: import { icons } from 'glyphfox' y provideGlyphFox({ icons }). Eso incluye los datos de los 419 iconos en el bundle que carga el proveedor, unos 105 KB minificados y 25 KB con gzip, así que resérvalo para prototipos y herramientas internas. Dos exportaciones de datos con nombre ocupan bastante menos de 1 KB.
Usa gf-icon
import { Component, signal } from '@angular/core'; import { GlyphFoxIcon } from 'glyphfox-angular'; @Component({ selector: 'app-toolbar', standalone: true, // the default from Angular 19 imports: [GlyphFoxIcon], template: ` <a href="/" aria-label="Home"><gf-icon name="home" /></a> <gf-icon name="search" size="20" /> <gf-icon name="file+check@tr" variant="duotone" secondaryColor="#ff7a1a" /> <button type="button" aria-label="Menu" [attr.aria-expanded]="open()" (click)="open.set(!open())"> <gf-icon name="menu" morphTo="x" trigger="state" [active]="open()" /> </button> `, }) export class Toolbar { readonly open = signal(false); }
Los inputs usan los nombres de las props en camelCase: secondaryColor, modifierCorner, flipX. Las cadenas estáticas sirven para cualquier input, incluidos los numéricos (size="20" se convierte en el número 20), y los inputs booleanos aceptan el atributo sin valor, así que <gf-icon name="arrow-right" mirrorRtl /> refleja la flecha en diseños de derecha a izquierda.
class y style se aplican al host gf-icon, una caja inline flex que envuelve el svg. Los trazos usan currentColor, así que el color CSS del host o de cualquier elemento padre colorea el icono, y el input color lo define directamente.
Modificadores, estilos y fusión
name acepta la sintaxis de nombres completa. file+check agrega una insignia, @tl, @tr, @bl o @br elige su esquina y heart/solid elige un estilo. Las insignias las dibuja el motor, así que solo hay que registrar el icono base. Para una fusión, pasa las partes a [icons] y elige un layout.
<gf-icon name="cloud+sync@tr" /> <gf-icon name="heart/solid" color="#e5484d" /> <gf-icon [icons]="['cloud', 'lock']" layout="overlap" [gap]="1" /> <gf-icon [icons]="['user', 'shield']" layout="badge" /> <gf-icon [icons]="['file', 'image', 'music', 'video']" layout="grid" />
Una fusión se resuelve por nombre como cualquier otro icono, así que todas sus partes deben estar registradas. El resultado respeta weight, variant y los demás inputs, y donde las partes se superponen, la que queda detrás se recorta alrededor de la que está delante. Las disposiciones son overlap, side, stack, grid, orbit, badge e inside.
Datos de icono en lugar de nombres
El input icon recibe directamente los datos del icono y se salta el registro, algo que encaja bien con iconos elegidos en el código a partir de un mapa fijo.
import { Component, computed, input } from '@angular/core'; import { iconFile, iconFileCode, iconFileImage, iconFileText } from 'glyphfox'; import { GlyphFoxIcon } from 'glyphfox-angular'; const byType = { code: iconFileCode, image: iconFileImage, text: iconFileText }; type FileType = keyof typeof byType; @Component({ selector: 'app-file-row', standalone: true, imports: [GlyphFoxIcon], template: `<gf-icon [icon]="icon()" size="18" /> {{ name() }}`, }) export class FileRow { readonly name = input.required<string>(); readonly type = input<FileType | null>(null); readonly icon = computed(() => { const type = this.type(); return type ? byType[type] : iconFile; }); }
Iconos para rutas con carga diferida
provideGlyphFox devuelve proveedores de entorno, así que también funciona en los providers de una ruta. Si lo declaras en un archivo de rutas con carga diferida, los iconos de esa funcionalidad viajan con el chunk diferido en lugar de con el bundle principal.
import { iconHome, iconMenu, iconSearch, iconX } from 'glyphfox'; import type { GlyphFoxConfig } from 'glyphfox-angular'; export const sharedIcons = { icons: [iconHome, iconSearch, iconMenu, iconX], defaults: { weight: 1.75 }, } satisfies GlyphFoxConfig;
import { Routes } from '@angular/router'; export const routes: Routes = [ { path: 'billing', loadChildren: () => import('./billing/billing.routes').then((m) => m.BILLING_ROUTES) }, ];
import { Routes } from '@angular/router'; import { iconCreditCard, iconReceipt, iconWallet } from 'glyphfox'; import { provideGlyphFox } from 'glyphfox-angular'; import { sharedIcons } from '../icons'; import { BillingPage } from './billing.page'; export const BILLING_ROUTES: Routes = [ { path: '', providers: [ provideGlyphFox({ ...sharedIcons, icons: [...sharedIcons.icons, iconCreditCard, iconReceipt, iconWallet] }), ], component: BillingPage, }, ];
Una ruta que llama a provideGlyphFox obtiene su propia configuración. Angular no combina los proveedores múltiples entre inyectores, así que los componentes bajo esa ruta solo leen la llamada de la ruta, incluidos sus valores predeterminados. Expandir un objeto compartido, como en el ejemplo anterior, conserva los iconos y los valores predeterminados de la raíz.
Renderizado en el servidor e hidratación
gf-icon escribe su svg mediante Renderer2, así que con Angular SSR o con prerenderizado el icono ya está en el HTML, y el navegador vuelve a dibujar el mismo marcado cuando el componente se inicializa. El servidor no tiene requestAnimationFrame: allí un morph salta directamente a su valor final, y un morph con el disparador predeterminado (mount) solo se reproduce cuando la aplicación arranca en el navegador.
Registra todos los iconos que renderiza el servidor. Un nombre sin registrar se carga con una importación dinámica, y esa solicitud puede seguir pendiente cuando el servidor serializa la página, lo que deja un icono vacío en el HTML hasta que la hidratación lo completa.
El mismo cargador explica un detalle de las compilaciones de producción: la salida muestra un pequeño chunk por icono, porque el builder empaqueta todos los destinos posibles de esa importación dinámica. Esos chunks solo se descargan para los nombres que no están registrados.
OnPush, signals y aplicaciones zoneless
gf-icon usa OnPush y dibuja su svg por sí mismo cada vez que cambia un input, con los disparadores hover y click, y en cada fotograma de un morph. No depende de zone.js, así que funciona en aplicaciones zoneless, y las signals se enlazan como cualquier otro valor: [active]="saved()".
import { Component, signal } from '@angular/core'; import { GlyphFoxIcon } from 'glyphfox-angular'; @Component({ selector: 'app-save-button', standalone: true, imports: [GlyphFoxIcon], template: ` <button type="button" (click)="save()"> <gf-icon name="save" morphTo="check" trigger="state" [active]="saved()" [duration]="300" /> {{ saved() ? 'Saved' : 'Save' }} </button> `, }) export class SaveButton { readonly saved = signal(false); save() { this.saved.set(true); setTimeout(() => this.saved.set(false), 1500); } }
Los presets de estados vivos funcionan igual: <gf-icon name="bell" animate="shake" trigger="state" [active]="hasNews()" /> hace oscilar la campana mientras la signal sea true, y animate="spin" en loader-circle crea un indicador de carga. Las animaciones son CSS dentro del svg y se detienen con movimiento reducido; la guía de iconos animados enumera todos los presets y disparadores.
Inputs
Cada prop compartida es un input con el mismo nombre y significado que en los demás paquetes de glyphfox.
| Input | Tipo | Por defecto | Descripción |
|---|---|---|---|
size | number, string | 24 | Ancho y alto; los números son píxeles. |
color | string | currentColor | Color principal. |
secondaryColor | string | color | Color de la capa duotone y del relleno sólido. |
secondaryOpacity | number | 0.3 / 1 | Opacidad de la capa duotone o del relleno sólido. |
weight | number | 2 | Trazo de 1 a 3 en la cuadrícula de 24, con compensación óptica por debajo de 24 px. |
absoluteWeight | boolean | false | Mantiene el trazo en weight píxeles a cualquier tamaño. |
corners | round, sharp | round | Uniones y extremos redondeados o rectos. |
variant | outline, duotone, solid | outline | Eje de estilo; solid se obtiene de las formas cerradas. |
rotate | number | 0 | Rotación en grados. |
flipX | boolean | false | Refleja en horizontal. |
flipY | boolean | false | Refleja en vertical. |
mirrorRtl | boolean | false | Refleja en layouts de derecha a izquierda. |
animate | draw, pop, wiggle, spin, pulse, bounce, shake | ninguno | Preset de estado vivo. |
trigger | mount, hover, click, state | mount | Cuándo se reproduce la animación o el morph. |
active | boolean | false | El estado para el disparador state. |
duration | number (ms) | según el preset | Duración de la animación o del morph. |
delay | number (ms) | 0 | Retraso de la animación o del morph. |
loop | boolean, number | false | Repite sin fin o un número de veces (spin y pulse se repiten por defecto). |
modifier | plus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dot | ninguno | Insignia con hueco de recorte automático. |
modifierCorner | top-left, top-right, bottom-left, bottom-right | bottom-right | Esquina de la insignia. |
morphTo | name, data | ninguno | Destino del morph; el disparador decide cuándo se muestra. |
title | string | ninguno | Nombre accesible: title, role img y aria-label. |
decorative | boolean | true sin title | Oculta el icono a las tecnologías de apoyo. |
Además de las props compartidas, gf-icon acepta name (cualquier especificación), icon (datos de icono), icons (de 2 a 10 partes de una fusión), layout y gap.
Errores comunes
- provideGlyphFox en un componente
- Devuelve proveedores de entorno, que van en la configuración de la aplicación, en un NgModule o en una ruta. Angular los rechaza en los
providersde un componente. - Una ruta con carga diferida pierde los valores predeterminados de la raíz
- Los proveedores de una ruta reemplazan la configuración de todo lo que hay bajo esa ruta, porque los proveedores múltiples no se combinan entre inyectores. Expande un objeto de configuración compartido en cada llamada.
- aria-label en el host
- Un
aria-labelengf-iconhace que el svg interior deje de ser decorativo (role="img"), pero la etiqueta se queda en el elemento host, que no tiene rol, así que los lectores de pantalla pueden no anunciar nada. Usa el inputtitlepara un icono significativo, o etiqueta el botón padre y deja el icono como decorativo. - Una fusión que nunca aparece
- Si una parte de
[icons]no está registrada, toda la fusión la espera y, mientras tanto, se renderiza vacía, también en el servidor. Registra todas las partes. - Registrar todo el conjunto sin querer
provideGlyphFox({ icons })con el objeto completo deglyphfoxmantiene todos los iconos en el bundle. En su lugar, importa las exportaciones de datos con nombre que necesites.
Preguntas frecuentes
¿Puedo usar glyphfox-angular en una aplicación basada en NgModule?
Sí. GlyphFoxIcon es un componente standalone, así que agrégalo a los imports del NgModule que declara tus componentes y pon provideGlyphFox(...) en los providers de tu módulo raíz.
¿Qué versiones de Angular son compatibles?
Angular 17 y versiones posteriores, el rango de la peer dependency del paquete. En las versiones 17 y 18, mantén standalone: true en los componentes que importan GlyphFoxIcon; a partir de la 19 es el valor predeterminado. Las etiquetas autocerradas como <gf-icon name="home" /> funcionan en todas las versiones compatibles.