Frameworks

Icons in Vue 3

Jedes glyphfox-Icon ist eine Vue-3-Komponente mit denselben Props wie in allen anderen glyphfox-Paketen. Dieser Leitfaden behandelt die Installation, Props in Templates, Icons per Name, Morphing, globale Registrierung, TypeScript und die Fehler, durch die ein Icon leer bleibt.

Installation

terminal
npm install glyphfox

glyphfox hat keine Abhängigkeiten. Vue 3.2 oder neuer ist eine optionale Peer-Dependency, die nur benötigt wird, wenn Sie glyphfox/vue importieren. Dasselbe Paket enthält auch die Builds für React, Svelte und die Web Component, Sie müssen also nichts weiter installieren.

Jedes Icon ist eine Komponente, die nach dem Icon in PascalCase mit dem Suffix Icon benannt ist: Aus arrow-right wird ArrowRightIcon, aus x wird XIcon. Der Icon-Browser zeigt den Namen jedes Icons und kopiert das Vue-Snippet für Sie.

Die Komponenten verwenden

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>

Die Props sind in camelCase deklariert, und Vue akzeptiert in Templates beide Schreibweisen: secondary-color und secondaryColor erreichen dieselbe Prop. Binden Sie Zahlen mit :size="20"; ein einfaches size="20" funktioniert ebenfalls, weil size, weight, rotate, duration und die anderen numerischen Props auch Strings akzeptieren.

Die Komponenten deklarieren weder class noch style noch Listener, daher reicht Vue diese an das Wurzelelement <svg> durch. Ihre Klassen werden mit den eingebauten Klassen glyphfox glyphfox-NAME zusammengeführt, und @click, aria-*, data-* und id landen direkt auf dem SVG-Element.

Striche verwenden currentColor, daher übernimmt ein Icon die CSS-Eigenschaft color seines Elternelements und folgt Hover-Zuständen und Themes ganz ohne Zusatzaufwand. Die Prop color setzt die Farbe direkt am SVG-Element, wenn Sie eine feste Farbe brauchen. Das SVG-Element erhält die Attribute width und height aus size (standardmäßig 24); CSS-Angaben für width und height in einer Klasse überschreiben sie.

Strichstärke, Ecken und Stil

Drei Props verändern die Zeichnung selbst, nicht die Box um sie herum: weight legt den Strich von 1 bis 3 fest, corners wechselt zwischen abgerundeten und spitzen Linienverbindungen, und variant wählt outline, duotone oder solid. Unter 24 px wird der Strich leicht verstärkt, damit kleine Icons nicht blass wirken; absolute-weight behält genau den angeforderten Strich bei.

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>

Der Solid-Stil wird beim Build aus den geschlossenen Formen jedes Icons erzeugt, wobei die inneren Linien als Negativraum ausgespart werden. Icons ohne geschlossene Formen behalten ihre Outline-Darstellung, wenn Sie solid anfordern.

Icons per Name, Modifier und Fusion

Icon rendert jede Angabe in der Namenssyntax: einen einfachen Namen, ein Modifier-Badge (file+check, mit @tl, @tr, @bl oder @br für die Ecke), eine Fusion (cloud&lock:overlap) oder einen Stil (heart/solid). Fusion nimmt eine Liste von Namen und ein Layout entgegen. Beide sind nützlich, wenn das Icon aus Daten stammt, etwa aus einer Menüdefinition, einem Statusfeld oder einem CMS.

Komponenten wie FileIcon bringen ihre eigenen Daten mit. Hinter einem Namen in einem String steht kein Import, registrieren Sie die Daten deshalb einmal mit registerIcons. Die Registry wird von Icon, Fusion, MorphIcon und jeder morph-to-Prop gemeinsam genutzt, sodass ein einziges Modul die ganze App abdeckt. Modifier-Badges zeichnet die Engine selbst, sie müssen nicht registriert werden.

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>

Eine Fusion ist ein echtes Icon: Sie folgt weight, variant und allen anderen Props, und wo sich die Teile überlappen, wird der hintere Teil rund um den vorderen ausgespart. Die Layouts sind overlap, side, stack, grid, orbit, badge und inside; mit scale und offsets justieren Sie die Teile fein.

Zwischen Icons morphen

Es gibt drei Wege zum Morphing. MorphIcon animiert, sobald sich sein name ändert. Jede Icon-Komponente akzeptiert morph-to mit einem Auslöser (mount, hover, click oder state). Und das Composable useMorph liefert die animierten Frames für Ihr eigenes Rendering.

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 akzeptiert einen Ref, einen Getter oder einen einfachen Wert und gibt einen berechneten Frame { icon, variant } zurück, der animiert wird, sobald sich die Angabe ändert. Übergeben Sie den Frame über die Prop icon an Icon, oder reichen Sie ihn an Ihren eigenen Renderer weiter.

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>

Von Hand abgestimmte Paare lassen gängige Übergänge wie bewusst gestaltet wirken: menu zu x, play zu pause, plus zu check, sun zu moon, eye zu eye-off, bell zu bell-ring, heart zu heart/solid, copy zu check, lock zu unlock und wifi zu wifi-off. Jedes andere Paar morpht trotzdem, und zwar über eine automatische Zuordnung. Der Leitfaden zu animierten Icons behandelt Dauer, Verzögerungen und reduzierte Bewegung.

Lebendige Zustände

Die Prop animate fügt ein Preset hinzu, das das Icon versteht: draw zeichnet die Striche in Zeichenreihenfolge nach, shake schwingt von oben, und pop, wiggle, spin, pulse und bounce tun, was ihr Name verspricht. Die Animation ist ein kleines Stylesheet im SVG-Element, braucht also keinen CSS-Import und stoppt für Besucher, die reduzierte Bewegung bevorzugen.

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>

Globale Registrierung

Wenn Sie Icons dort importieren, wo Sie sie verwenden, bleibt jedes Bundle klein. Braucht ein Designsystem in jedem Template einen festen Satz, registrieren Sie diese Komponenten einmal mit app.component. Geben Sie Icon einen eindeutigen Namen wie GfIcon, damit es nicht mit einer anderen globalen Komponente kollidieren kann.

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');

Mit TypeScript deklarieren Sie die globalen Komponenten, damit die Templates geprüft werden:

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

Jede Komponente ist als GlyphComponent mit den gemeinsamen Props typisiert, daher vervollständigen Editoren variant, modifier, animate und alle weiteren Props. Icon-Angaben sind in den Vue-Typen einfache Strings, weil die Prop-Inferenz von Vue die vollständige Union der Icon-Namen nicht auflösen kann. Wenn Sie Namen in Ihrem eigenen Code verwalten, typisieren Sie sie mit IconName aus glyphfox, um Tippfehler schon beim Kompilieren abzufangen.

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' },
];

Deep Imports und Bundle-Größe

Benannte Importe aus glyphfox/vue unterliegen dem Tree-Shaking: Die Icon-Module sind als frei von Seiteneffekten markiert, und jede Komponente wird mit einem Pure-Aufruf erzeugt. In einem Vite-8-Produktionsbuild (ohne Vue selbst) kommen eine Icon-Komponente und die gemeinsame Runtime auf etwa 53 KB minifiziert bzw. 20 KB mit gzip, und neun weitere Icons fügen weniger als 1 KB (gzip) hinzu. Die Runtime enthält die Engines für Rendering, Morph, Fusion und Modifier und fällt nur einmal an.

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>

Der Leitfaden zum Tree-Shaking erklärt, was das komplette Set aus Ihrem Bundle heraushält und was es wieder hineinzieht.

Props

Alle Icon-Komponenten sowie Icon, Fusion und MorphIcon akzeptieren die gemeinsamen Props. In Templates können Sie das Attribut in kebab-case aus der zweiten Spalte verwenden.

PropIn TemplatesTypStandardBeschreibung
sizesizenumber, string24Breite und Höhe; Zahlen sind Pixel.
colorcolorstringcurrentColorHauptfarbe.
secondaryColorsecondary-colorstringcolorFarbe der Duotone-Ebene und der Solid-Füllung.
secondaryOpacitysecondary-opacitynumber0.3 / 1Deckkraft der Duotone-Ebene oder der Solid-Füllung.
weightweightnumber2Strichstärke von 1 bis 3 im 24er-Raster, unter 24 px optisch ausgeglichen.
absoluteWeightabsolute-weightbooleanfalseHält den Strich bei jeder Größe auf weight Pixeln.
cornerscornersround, sharproundAbgerundete oder spitze Verbindungen und Enden.
variantvariantoutline, duotone, solidoutlineStilachse; solid entsteht aus den geschlossenen Formen.
rotaterotatenumber0Drehung in Grad.
flipXflip-xbooleanfalseHorizontal spiegeln.
flipYflip-ybooleanfalseVertikal spiegeln.
mirrorRtlmirror-rtlbooleanfalseIn Layouts von rechts nach links spiegeln.
animateanimatedraw, pop, wiggle, spin, pulse, bounce, shakekeinerVoreinstellung für den lebendigen Zustand.
triggertriggermount, hover, click, statemountWann die Animation oder der Morph abläuft.
activeactivebooleanfalseDer Zustand für den Auslöser state.
durationdurationnumber (ms)je nach VoreinstellungDauer der Animation oder des Morphs.
delaydelaynumber (ms)0Verzögerung der Animation oder des Morphs.
looploopboolean, numberfalseEndlos oder eine bestimmte Anzahl von Malen wiederholen (spin und pulse laufen standardmäßig in Schleife).
modifiermodifierplus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dotkeinerBadge mit automatischer Aussparung.
modifierCornermodifier-cornertop-left, top-right, bottom-left, bottom-rightbottom-rightEcke des Badges.
morphTomorph-toname, datakeinerZiel des Morphs; der Auslöser bestimmt, wann es erscheint.
titletitlestringkeinerZugänglicher Name: title, role img und aria-label.
decorativedecorativebooleantrue ohne titleVerbirgt das Icon vor assistiven Technologien.

Icon ergänzt name, icon (Icon-Daten) und gap. Fusion ergänzt icons, layout, gap, scale und offsets. MorphIcon ergänzt name und icon. Ein Default-Slot wird innerhalb des SVG-Elements gerendert.

Stolperfallen

Ein per Name verwendetes Icon ist im Produktionsbuild leer
Der Dev-Server bündelt das gesamte Paket vorab, daher wird während der Entwicklung jeder Name aufgelöst. Ein Produktionsbuild behält nur, was Sie importieren, und Vite bündelt den On-Demand-Loader in node_modules nicht mit: Nicht registrierte Namen in Icon, Fusion, MorphIcon oder morph-to rendern ein leeres SVG. Registrieren Sie sie mit registerIcons, wie oben in src/icons.js.
Reine Icon-Buttons ohne zugänglichen Namen
Icons sind standardmäßig dekorativ und erhalten aria-hidden="true". Ein Button, der nur ein Icon enthält, hat daher keinen zugänglichen Namen. Setzen Sie aria-label auf den Button, oder geben Sie dem Icon einen title. Weitere Muster finden Sie im Leitfaden zur Barrierefreiheit.
morph-to startet sofort beim Laden der Seite
Der Standard-Auslöser ist mount: Das Icon morpht direkt nach dem Mounten zu seinem Ziel. Wenn das Ziel der Zustand ist, den Sie sofort zeigen möchten, verwenden Sie trigger="state" mit :active; damit steht das Icon ohne Animation sofort im richtigen Endzustand.
Boolesche Props als Strings
active="false" übergibt den String „false“. glyphfox liest ihn als false, aber Vue warnt wegen des Prop-Typs. Schreiben Sie boolesche Props ohne Wert (flip-x) oder binden Sie sie (:active="playing").
Wildcard-Importe
import * as icons from 'glyphfox/vue' gefolgt von icons[name] hält jedes Icon im Bundle, weil der Bundler nicht wissen kann, welche Namen Sie auslesen. Legen Sie stattdessen eine kleine Map mit den Komponenten an, die Sie brauchen.

Häufige Fragen

Funktioniert glyphfox mit Vue 2?

Die Komponenten benötigen Vue 3.2 oder neuer. Verwenden Sie in einer Vue-2-App die Web Component <glyph-fox>, die dieselben Props als Attribute akzeptiert; fügen Sie glyph-fox zu Vue.config.ignoredElements hinzu, damit Vue das Tag nicht anrührt. Mehr dazu im Leitfaden zu Web Components.

Kann ich die Komponenten mit der Options API verwenden?

Ja. Es sind ganz normale Komponenten: Führen Sie sie in components: { HomeIcon } auf und verwenden Sie sie im Template. useMorph ist ein Composable und gehört daher in setup().

Können meine eigenen SVG-Icons dieselben Props erhalten?

Ja. createIcon({ name, body, tags, categories }) aus glyphfox/vue macht aus Icon-Daten eine Komponente, wobei body das innere Markup eines Strich-Icons im Format 24 mal 24 ist. Lassen Sie Ihr SVG zuerst im Studio durch Fox-ify laufen, damit es die Raster-, Strich- und Padding-Regeln einhält, auf die die Strichstärke und die anderen Achsen angewiesen sind.

Icons in diesem Leitfaden