Iconos en Svelte 5
glyphfox/svelte incluye un componente de Svelte 5 por icono, además de Icon, Fusion y MorphIcon, con las mismas props que todos los demás paquetes de glyphfox.
Instalación
npm install glyphfox
Los componentes son archivos fuente .svelte que compila tu aplicación, así que el proceso de compilación necesita Svelte 5 y su compilador, normalmente a través de vite-plugin-svelte, que ya viene en todos los proyectos de SvelteKit. Están escritos con runes como $props y $state, así que Svelte 4 no puede compilarlos.
svelte 5 es una peer dependency opcional de glyphfox: solo la necesitas cuando importas glyphfox/svelte. El paquete expone esa entrada bajo la condición de exportación svelte, que vite-plugin-svelte usa para reconocer una biblioteca de Svelte y compilar sus componentes para el navegador y el servidor.
Usa los componentes
<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 icono es un componente con el nombre del icono en PascalCase y el sufijo Icon: arrow-right se convierte en ArrowRightIcon y loader-circle en LoaderCircleIcon. Las props usan los nombres en camelCase, exactamente como en JavaScript, porque Svelte pasa las props a los componentes tal como se escriben.
class y style se aplican al svg, y cualquier otro atributo, como aria-*, data-* o id, se le pasa mediante spread. En Svelte 5, los controladores de eventos son props: onclick, onmouseenter y onmouseleave se reenvían, y siguen ejecutándose cuando el icono tiene un disparador click o hover.
Los trazos usan currentColor, así que el icono sigue el color CSS de su elemento padre. La prop color fija un color concreto en el svg.
Peso, esquinas y estilo
weight define el trazo de 1 a 3, corners alterna entre uniones redondeadas y rectas, y variant elige el estilo outline, duotone o solid. Por debajo de 24 px, el trazo se engrosa ligeramente para que los iconos pequeños conserven su presencia; absoluteWeight mantiene el valor exacto.
<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 y fusión
Icon renderiza cualquier especificación de la sintaxis de nombres: un nombre, una insignia de modificador (file+check, con @tl, @tr, @bl o @br para la esquina), una fusión (cloud&lock:overlap) o un estilo (heart/solid). Fusion recibe una lista de nombres y una disposición: overlap, side, stack, grid, orbit, badge o inside.
Los componentes de icono llevan sus propios datos: cada uno registra su icono en un bloque <script module>. Un nombre dentro de una cadena no tiene ninguna importación detrás, así que registra esos nombres una vez con registerIcons. Las insignias de modificador las dibuja el motor y no necesitan registro.
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]);
<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} />
Importa el módulo de registro desde tu archivo de entrada o tu componente raíz. Un componente también puede registrar iconos en su propio bloque <script module>, que se ejecuta una vez cuando se carga el módulo y no una vez por instancia.
MorphIcon, morphTo y morphStore
MorphIcon se anima cada vez que cambia su name, algo que encaja de forma natural con $state:
<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>
Cualquier componente de icono acepta también morphTo con un disparador: click alterna en cada clic, hover sigue al puntero, state sigue a active, y el predeterminado, mount, se transforma una vez después de montarse.
<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) es un store para renderizado personalizado. Llama a set(name) para iniciar un morph y lee $store, un fotograma con icon y variant que puedes pasar a Icon.
<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>
Hay pares ajustados a mano para las transiciones de menu a x, de play a pause, de plus a check, de sun a moon, de eye a eye-off, de bell a bell-ring, de heart a heart/solid, de copy a check, de lock a unlock y de wifi a wifi-off. Los demás pares se transforman con una correspondencia automática.
Animaciones controladas por el estado
Los estados vivos son presets que entienden el icono: draw recorre los trazos en el orden en que se dibujan, shake lo hace oscilar desde arriba, y pop, wiggle, spin, pulse y bounce completan el conjunto. Con trigger="state", una animación se reproduce mientras active sea true, así que sigue directamente a tus runes.
<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 es una pequeña hoja de estilos dentro del svg, así que no necesita importar CSS y se detiene para los visitantes que prefieren movimiento reducido. La guía de iconos animados trata las duraciones, los retrasos y los bucles.
Importaciones profundas y tipos
glyphfox/svelte reexporta todos los componentes, y las compilaciones de producción descartan los que no importas. Una importación profunda se resuelve en un único archivo .svelte, lo que limita el código que ven tu compilador y tu servidor de desarrollo a lo que usas:
<script> import FoxIcon from 'glyphfox/svelte/icons/fox'; </script> <FoxIcon size={32} variant="duotone" title="glyphfox" />
Los tipos vienen incluidos en el paquete. Cada componente es un Component<GlyphProps>, donde GlyphProps son las props compartidas más cualquier atributo SVG, así que un componente envoltorio tipado puede reenviarlo todo:
<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} />
Los nombres tipados como IconName se comprueban en tiempo de compilación, pero siguen necesitando estar registrados para renderizarse: consulta los errores comunes más abajo y la guía de tree shaking.
Props
Todos los componentes de icono, Icon, Fusion y MorphIcon aceptan las props compartidas, en camelCase.
| Prop | 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. |
Icon agrega name, icon (datos de icono) y gap. Fusion agrega icons, layout, gap, scale y offsets. MorphIcon agrega icon y name. Los hijos se renderizan dentro del svg.
Errores comunes
- Las props en kebab-case no hacen nada
- En Svelte,
secondary-color="#ff7a1a"no es la propsecondaryColor: se aplica al svg como un atributo normal y el icono conserva su valor predeterminado. Usa los nombres en camelCase en todas partes. - Nombres que funcionan en desarrollo y desaparecen en producción
- Durante el desarrollo, Vite preempaqueta el paquete y todos los nombres se resuelven. Una compilación de producción solo conserva lo que importas, y Vite no incluye en el bundle el cargador bajo demanda que está dentro de
node_modules, así que los nombres sin registrar enIcon,Fusion,MorphIcon,morphToymorphStorerenderizan un svg vacío. Regístralos. - morphStore creado antes del registro
morphStoreresuelve un nombre cuando llamas aset. Si en ese momento el nombre no está registrado, lo que hace es esperar al cargador. Importa el módulo de registro antes de crear el store, como en el ejemplo anterior.- Importaciones con asterisco y búsquedas dinámicas
import * as icons from 'glyphfox/svelte'conicons[name]mantiene todos los componentes en el bundle. Crea un mapa con los componentes que necesitas o usaIconcon nombres registrados.
Preguntas frecuentes
¿Puedo usar glyphfox en un proyecto con Svelte 4?
No con glyphfox/svelte, que necesita el compilador de Svelte 5. En una aplicación con Svelte 4 funciona el web component <glyph-fox>, con las mismas props como atributos; consulta la guía de web components.
¿Los componentes necesitan SvelteKit?
No. Sirve cualquier configuración de Svelte 5 que compile archivos .svelte, como un proyecto básico de Vite con vite-plugin-svelte. SvelteKit agrega el renderizado en el servidor y el prerenderizado, que se explican en la guía de SvelteKit.