Frameworks

Iconos en Vue 3

Cada icono de glyphfox es un componente de Vue 3 con las mismas props que en todos los demás paquetes de glyphfox. Esta guía cubre la instalación, las props en plantillas, los iconos por nombre, el morph, el registro global, TypeScript y los errores que dejan un icono vacío.

Instalación

terminal
npm install glyphfox

glyphfox no tiene dependencias. Vue 3.2 o posterior es una peer dependency opcional, que solo necesitas cuando importas glyphfox/vue. El mismo paquete contiene también las compilaciones para React, Svelte y el web component, así que no hay que instalar nada más.

Cada icono es un componente con el nombre del icono en PascalCase y el sufijo Icon: arrow-right se convierte en ArrowRightIcon y x en XIcon. El explorador de iconos muestra el nombre de cada icono y te copia el fragmento de código para Vue.

Usa los componentes

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

defineProps({ unread: { type: Number, default: 0 } });
</script>

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

Las props se declaran en camelCase, y Vue acepta las dos formas en las plantillas: secondary-color y secondaryColor llegan a la misma prop. Vincula los números con :size="20"; un simple size="20" también funciona, porque size, weight, rotate, duration y las demás props numéricas aceptan cadenas.

Los componentes no declaran class, style ni listeners, así que Vue los pasa al <svg> raíz. Tus clases se combinan con las clases integradas glyphfox glyphfox-NAME, y @click, id, aria-* y data-* llegan al propio svg.

Los trazos usan currentColor, así que un icono toma el color CSS de su elemento padre y sigue los estados hover y los temas sin trabajo extra. La prop color aplica el color en el svg cuando necesitas uno fijo. El svg recibe los atributos width y height a partir de size (24 por defecto); el ancho y el alto definidos con CSS en una clase tienen prioridad sobre ellos.

Peso, esquinas y estilo

Tres props cambian el dibujo en sí y no la caja que lo rodea: 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 no se vean tenues; absolute-weight mantiene exactamente el trazo que indicas.

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

<template>
  <FolderIcon :weight="1" />
  <FolderIcon :weight="3" corners="sharp" />
  <FolderIcon variant="duotone" secondary-color="#ff7a1a" />
  <FolderIcon variant="solid" />
  <FolderIcon :size="16" :weight="1.5" absolute-weight />
</template>

El estilo sólido se genera en tiempo de compilación a partir de las formas cerradas de cada icono, con las líneas interiores recortadas como espacio negativo. Los iconos sin formas cerradas conservan su contorno cuando pides solid.

Iconos por nombre, modificadores y fusión

Icon renderiza cualquier especificación de la sintaxis de nombres: un nombre simple, 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. Ambos son útiles cuando el icono viene de los datos, como la definición de un menú, un campo de estado o un CMS.

Los componentes como FileIcon traen sus propios datos. Un nombre dentro de una cadena no tiene ninguna importación detrás, así que registra los datos una vez con registerIcons. El registro lo comparten Icon, Fusion, MorphIcon y todas las props morph-to, así que un solo módulo cubre toda la aplicación. Las insignias de modificador las dibuja el motor y no necesitan registro.

src/icons.js
import { registerIcons } from 'glyphfox/vue';
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 pause from 'glyphfox/icons/pause';

// Every name used in a string: Icon, Fusion, MorphIcon and morph-to.
registerIcons([file, cloud, lock, menu, x, pause]);
src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import './icons.js';

createApp(App).mount('#app');
FileStatus.vue
<script setup>
import { Icon, Fusion } from 'glyphfox/vue';

defineProps({ saved: Boolean });
</script>

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

Una fusión es un icono de verdad: respeta weight, variant y todas las demás props, 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; scale y offsets ajustan con precisión las partes.

Morph entre iconos

Hay tres formas de transformar iconos. MorphIcon se anima cada vez que cambia su name. Cualquier componente de icono acepta morph-to con un disparador (mount, hover, click o state). Y el composable useMorph devuelve los fotogramas animados para tu propio renderizado.

MenuButton.vue
<script setup>
import { ref } from 'vue';
import { MorphIcon } from 'glyphfox/vue';

const open = ref(false);
</script>

<template>
  <button type="button" aria-label="Menu" :aria-expanded="open" @click="open = !open">
    <MorphIcon :name="open ? 'x' : 'menu'" :duration="300" />
  </button>
</template>
Triggers.vue
<script setup>
import { HeartIcon, PlayIcon } from 'glyphfox/vue';

defineProps({ playing: Boolean });
</script>

<template>
  <!-- toggles on every click -->
  <HeartIcon morph-to="heart/solid" trigger="click" />
  <!-- shows pause while playing is true -->
  <PlayIcon morph-to="pause" trigger="state" :active="playing" />
</template>

useMorph acepta una ref, un getter o un valor simple y devuelve un fotograma computado { icon, variant } que se anima cada vez que cambia la especificación. Pasa el fotograma a Icon mediante su prop icon o entrégaselo a tu propio renderizador.

PlayToggle.vue
<script setup>
import { ref } from 'vue';
import { Icon, useMorph } from 'glyphfox/vue';

const playing = ref(false);
const frame = useMorph(() => (playing.value ? 'pause' : 'play'), { duration: 250 });
</script>

<template>
  <button type="button" aria-label="Play" :aria-pressed="playing" @click="playing = !playing">
    <Icon v-if="frame" :icon="frame.icon" :variant="frame.variant" />
  </button>
</template>

Los pares ajustados a mano hacen que las transiciones habituales parezcan diseñadas expresamente: 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. Cualquier otro par se transforma igualmente mediante una correspondencia automática. La guía de iconos animados trata las duraciones, los retrasos y el movimiento reducido.

Estados vivos

La prop animate agrega un preset que entiende 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 hacen lo que indica su nombre. La animación 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.

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

defineProps({ hasNews: Boolean, loading: Boolean });
</script>

<template>
  <BellIcon animate="shake" trigger="state" :active="hasNews" />
  <LoaderCircleIcon v-if="loading" animate="spin" />
  <SparklesIcon animate="draw" trigger="hover" />
</template>

Registro global

Importar los iconos donde los usas mantiene pequeño cada bundle. Cuando un sistema de diseño necesita un conjunto fijo en todas las plantillas, registra esos componentes una vez con app.component. Dale a Icon un nombre distintivo, como GfIcon, para que no pueda chocar con otro componente global.

src/main.js
import { createApp } from 'vue';
import { HomeIcon, SearchIcon, SettingsIcon, Icon } from 'glyphfox/vue';
import App from './App.vue';
import './icons.js';

const app = createApp(App);
app.component('HomeIcon', HomeIcon);
app.component('SearchIcon', SearchIcon);
app.component('SettingsIcon', SettingsIcon);
app.component('GfIcon', Icon);
app.mount('#app');

Con TypeScript, declara los componentes globales para que las plantillas tengan comprobación de tipos:

src/glyphfox.d.ts
import type { HomeIcon, SearchIcon, SettingsIcon, Icon } from 'glyphfox/vue';

declare module 'vue' {
  interface GlobalComponents {
    HomeIcon: typeof HomeIcon;
    SearchIcon: typeof SearchIcon;
    SettingsIcon: typeof SettingsIcon;
    GfIcon: typeof Icon;
  }
}

export {};

TypeScript

Cada componente está tipado como GlyphComponent con las props compartidas, así que los editores autocompletan variant, modifier, animate y las demás. En los tipos de Vue, las especificaciones de icono son cadenas simples, porque la inferencia de props de Vue no puede expandir la unión completa de nombres de iconos. Cuando guardes nombres en tu propio código, asígnales el tipo IconName de glyphfox para detectar erratas en tiempo de compilación.

src/nav.ts
import type { IconName } from 'glyphfox';

export const nav: { label: string; to: string; icon: IconName }[] = [
  { label: 'Home', to: '/', icon: 'home' },
  { label: 'Search', to: '/search', icon: 'search' },
  { label: 'Settings', to: '/settings', icon: 'settings' },
];

Importaciones profundas y tamaño del bundle

Las importaciones con nombre de glyphfox/vue son compatibles con tree shaking: los módulos de iconos están marcados como libres de efectos secundarios y cada componente se crea con una llamada pura. En una compilación de producción con Vite 8 (sin contar el propio Vue), un componente de icono y el runtime compartido suman unos 53 KB minificados, 20 KB con gzip, y nueve iconos más agregan menos de 1 KB con gzip. El runtime incluye el renderizador y los motores de morph, fusión y modificadores, y se paga una sola vez.

Logo.vue
<script setup>
// One module, for tools that do not tree shake.
import { FoxIcon } from 'glyphfox/vue/icons/fox';
</script>

<template>
  <FoxIcon :size="32" variant="duotone" title="glyphfox" />
</template>

La guía de tree shaking explica qué mantiene el conjunto fuera de tu bundle y qué hace que vuelva a entrar.

Props

Todos los componentes de icono, Icon, Fusion y MorphIcon aceptan las props compartidas. En las plantillas puedes escribir el atributo en kebab-case de la segunda columna.

PropEn plantillasTipoPor defectoDescripción
sizesizenumber, string24Ancho y alto; los números son píxeles.
colorcolorstringcurrentColorColor principal.
secondaryColorsecondary-colorstringcolorColor de la capa duotone y del relleno sólido.
secondaryOpacitysecondary-opacitynumber0.3 / 1Opacidad de la capa duotone o del relleno sólido.
weightweightnumber2Trazo de 1 a 3 en la cuadrícula de 24, con compensación óptica por debajo de 24 px.
absoluteWeightabsolute-weightbooleanfalseMantiene el trazo en weight píxeles a cualquier tamaño.
cornerscornersround, sharproundUniones y extremos redondeados o rectos.
variantvariantoutline, duotone, solidoutlineEje de estilo; solid se obtiene de las formas cerradas.
rotaterotatenumber0Rotación en grados.
flipXflip-xbooleanfalseRefleja en horizontal.
flipYflip-ybooleanfalseRefleja en vertical.
mirrorRtlmirror-rtlbooleanfalseRefleja en layouts de derecha a izquierda.
animateanimatedraw, pop, wiggle, spin, pulse, bounce, shakeningunoPreset de estado vivo.
triggertriggermount, hover, click, statemountCuándo se reproduce la animación o el morph.
activeactivebooleanfalseEl estado para el disparador state.
durationdurationnumber (ms)según el presetDuración de la animación o del morph.
delaydelaynumber (ms)0Retraso de la animación o del morph.
looploopboolean, numberfalseRepite sin fin o un número de veces (spin y pulse se repiten por defecto).
modifiermodifierplus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dotningunoInsignia con hueco de recorte automático.
modifierCornermodifier-cornertop-left, top-right, bottom-left, bottom-rightbottom-rightEsquina de la insignia.
morphTomorph-toname, dataningunoDestino del morph; el disparador decide cuándo se muestra.
titletitlestringningunoNombre accesible: title, role img y aria-label.
decorativedecorativebooleantrue sin titleOculta 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. El slot por defecto se renderiza dentro del svg.

Errores comunes

Un icono usado por nombre aparece vacío en producción
El servidor de desarrollo preempaqueta todo el paquete, así que todos los nombres se resuelven mientras desarrollas. Una compilación de producción solo conserva lo que importas, y Vite no incluye en el bundle el cargador bajo demanda que está en node_modules: los nombres sin registrar en Icon, Fusion, MorphIcon o morph-to renderizan un svg vacío. Regístralos con registerIcons, como en el archivo src/icons.js de más arriba.
Botones con solo un icono y sin nombre accesible
Los iconos son decorativos por defecto y reciben aria-hidden="true". Por lo tanto, un botón que solo contiene un icono no tiene nombre accesible. Pon aria-label en el botón o dale al icono un title. Encontrarás más patrones en la guía de accesibilidad.
morph-to se reproduce en cuanto carga la página
El disparador predeterminado es mount: el icono se transforma en su destino justo después de montarse. Cuando el destino es el estado que quieres mostrar de inmediato, usa trigger="state" con :active, que empieza directamente en el extremo correcto, sin animación.
Props booleanas escritas como cadenas
active="false" pasa la cadena "false". glyphfox la interpreta como false, pero Vue muestra una advertencia sobre el tipo de la prop. Escribe las props booleanas sin valor (flip-x) o vincúlalas (:active="playing").
Importaciones con asterisco
import * as icons from 'glyphfox/vue' seguido de icons[name] mantiene todos los iconos en el bundle, porque el bundler no puede saber qué nombres lees. En su lugar, crea un pequeño mapa con los componentes que necesitas.

Preguntas frecuentes

¿Funciona glyphfox con Vue 2?

Los componentes necesitan Vue 3.2 o posterior. En una aplicación con Vue 2, usa el web component <glyph-fox>, que acepta las mismas props como atributos; agrega glyph-fox a Vue.config.ignoredElements para que Vue no toque la etiqueta. Consulta la guía de web components.

¿Puedo usar los componentes con la API de Opciones?

Sí. Son componentes normales: inclúyelos en components: { HomeIcon } y úsalos en la plantilla. useMorph es un composable, así que va dentro de setup().

¿Pueden mis propios iconos SVG tener las mismas props?

Sí. createIcon({ name, body, tags, categories }) de glyphfox/vue convierte datos de icono en un componente, donde body es el marcado interior de un icono de trazo de 24 por 24. Antes, pasa tu SVG por Fox-ify en el Estudio para que siga las reglas de cuadrícula, trazo y margen interior en las que se basan el peso y los demás ejes.

Iconos de esta guía