Frameworks

Icons in Astro

Astro rendert Komponenten auf dem Server oder zur Build-Zeit zu HTML, und das passt gut zu SVG-Icons: Rufen Sie den Renderer im Frontmatter auf, und die Seite erhält reines Inline-SVG ohne Client-JavaScript. Islands und das Custom Element decken die Icons ab, die reagieren müssen.

Installation

Installieren Sie das Paket. Statische Icons benötigen keine Astro-Integration, weil glyphfox aus reinen ES-Modulen besteht, die im Frontmatter laufen. Islands, die mit glyphfox/react, glyphfox/vue oder glyphfox/svelte gebaut sind, benötigen die passende Astro-Integration.

terminal
npm install glyphfox
# only for islands
npx astro add react

Icons im Frontmatter

Code im Frontmatter läuft auf dem Server, bei statischen Seiten zur Build-Zeit. toSvg gibt für jeden Icon-Namen den SVG-String zurück, und set:html schreibt ihn ohne Escaping in die Seite:

src/pages/index.astro
---
import { toSvg } from 'glyphfox';

const search = toSvg('search', { size: 20 });
---
<label class="search">
  <Fragment set:html={search} />
  <input type="search" name="q" aria-label="Search the docs" />
</label>

toSvg versteht die vollständige Namenssyntax, sodass Badges, Fusionen und Stile in einen einzigen String passen: toSvg('file+check@tr'), toSvg('cloud&lock:overlap'), toSvg('heart/solid').

Der Import von glyphfox lädt alle Icons, allerdings nur auf dem Server oder im Build. Nichts davon erreicht den Browser, weil das Frontmatter dort nie ausgeführt wird.

Eine Icon.astro-Komponente

Kapseln Sie den Aufruf in einer Komponente, damit Seiten Props statt Optionen übergeben. Das SVG landet direkt im Elternelement, ohne Wrapper-Element:

src/components/Icon.astro
---
import { toSvg, type SvgOptions } from 'glyphfox';

interface Props extends SvgOptions {
  name: string;
}

const { name, ...options } = Astro.props;
const svg = toSvg(name, options);
---
<Fragment set:html={svg} />
src/components/Nav.astro
---
import Icon from './Icon.astro';
---
<nav class="nav">
  <a href="/"><Icon name="home" size={20} /> Home</a>
  <a href="/docs/"><Icon name="book-open" size={20} weight={1.5} /> Docs</a>
  <a href="/new/"><Icon name="file+plus" size={20} title="New file" /></a>
</nav>

<style>
  .nav :global(.glyphfox) { color: #6b7280; }
  .nav a:hover :global(.glyphfox) { color: #111827; }
</style>

Jedes svg-Element trägt die Klassen glyphfox und glyphfox-NAME. Markup, das mit set:html eingefügt wird, erhält nicht die Attribute, die Astro für das Scoping von Komponenten-Styles verwendet. Wählen Sie es daher wie oben mit :global() innerhalb eines gescopten Eltern-Selektors aus, oder lassen Sie es color über currentColor erben.

Der Icon-Link oben hat keinen Text, daher erhält sein Icon einen title: Das ergänzt role="img", aria-label und ein <title>, und der Link bezieht seinen Namen daraus. Icons neben sichtbarem Text bleiben dekorativ. Weitere Muster finden Sie in der Anleitung zur Barrierefreiheit.

Animationen ohne JavaScript

Das SVG kann sein eigenes CSS mitbringen, daher laufen lebendige Zustände und Hover-Morphs in statischem HTML ganz ohne Skript: animate mit dem Standardwert trigger="mount" oder mit "hover" sowie morphTo mit trigger="hover", das auf das svg-Element und auf sein direktes Elternelement reagiert.

src/components/Chapter.astro
---
import Icon from './Icon.astro';
---
<a class="next" href="/chapter-2/">
  Next chapter <Icon name="arrow-right" morphTo="chevron-right" trigger="hover" />
</a>

<p class="status">
  <Icon name="loader" animate="spin" title="Building" /> Building the preview
</p>

Da Icon.astro keinen Wrapper hinzufügt, ist das svg-Element ein direktes Kind des Links, und ein Hover an beliebiger Stelle über dem Link morpht den Pfeil. Jedes Preset hält bei prefers-reduced-motion an; Presets und Auslöser sind unter Animierte Icons aufgeführt.

Islands für Zustände

Icons, die einem Zustand folgen, etwa ein Menü-Button, der zu einem Schließen-Icon morpht, gehören in eine Island. Verwenden Sie das Framework-Paket der Island und hydrieren Sie sie mit einer Client-Direktive:

src/components/MenuButton.jsx
import { useState } from 'react';
import { MorphIcon, registerIcons } from 'glyphfox/react';
import menu from 'glyphfox/icons/menu';
import x from 'glyphfox/icons/x';

// Names passed to MorphIcon load on demand; registering them
// puts the icon in the server rendered HTML.
registerIcons([menu, x]);

export default function MenuButton() {
  const [open, setOpen] = useState(false);
  return (
    <button
      type="button"
      aria-expanded={open}
      aria-label={open ? 'Close menu' : 'Open menu'}
      onClick={() => setOpen(!open)}
    >
      <MorphIcon name={open ? 'x' : 'menu'} duration={300} />
    </button>
  );
}
src/layouts/Base.astro
---
import MenuButton from '../components/MenuButton.jsx';
---
<header>
  <MenuButton client:load />
</header>

Astro rendert Islands zuerst auf dem Server. Icon-Komponenten wie MenuIcon registrieren ihr Icon, sobald Ihr Code sie verwendet, aber Namen, die an MorphIcon, Icon oder morphTo übergeben werden, werden erst bei Bedarf geladen. Ohne registerIcons enthält das Server-HTML daher ein leeres SVG, bis die Island hydriert ist.

Dasselbe funktioniert mit glyphfox/vue und mit glyphfox/svelte, das Svelte 5 voraussetzt. Bei Islands unterhalb des sichtbaren Bereichs verzögert client:visible oder client:idle den Download, bis er gebraucht wird. Details zu den Frameworks finden Sie in den Anleitungen zu React, Vue und Svelte.

Das Custom Element

Ohne Framework übernimmt das Element <glyph-fox> Klicks, Hover und Namenswechsel. Astro verarbeitet und bündelt die <script>-Tags von Komponenten und bindet jedes Skript nur einmal pro Seite ein, auch wenn die Komponente mehrfach vorkommt:

src/components/LikeButton.astro
<button type="button" class="like" aria-pressed="false" aria-label="Like">
  <glyph-fox name="heart" morph-to="heart/solid" trigger="state"></glyph-fox>
</button>

<script>
  import { defineGlyphFox } from 'glyphfox/web/element';
  import { registerIcons } from 'glyphfox/core';
  import heart from 'glyphfox/icons/heart';

  registerIcons([heart]);
  defineGlyphFox();

  for (const button of document.querySelectorAll('button.like')) {
    const icon = button.querySelector('glyph-fox');
    button.addEventListener('click', () => {
      const on = button.getAttribute('aria-pressed') !== 'true';
      button.setAttribute('aria-pressed', String(on));
      icon.toggleAttribute('active', on);
    });
  }
</script>

Der Button steuert das Icon über trigger="state" und das Attribut active. Mit trigger="click" würde das Element nur auf Klicks auf sich selbst reagieren, und ein Klick auf das Padding des Buttons würde aria-pressed umschalten, ohne das Icon zu morphen.

Custom Elements bleiben bei clientseitiger Navigation mit dem View-Transitions-Router von Astro definiert, daher führen Icons auf neuen Seiten ihr Upgrade von selbst durch. Code, der Listener anhängt, wie die Schleife oben, läuft nur einmal; mit dem Router führen Sie ihn beim Event astro:page-load erneut aus.

Tailwind-Klassen

Ist Tailwind CSS im Projekt eingerichtet, zeichnet das glyphfox-Plugin Icons als CSS-Masken: eine weitere Option ohne JavaScript, praktisch in inhaltsreichen Templates. Einrichtung und Klassensyntax beschreibt die Tailwind-Anleitung.

src/components/Hero.astro
<h1 class="flex items-center gap-3">
  <span class="gf-rocket text-4xl text-orange-500" aria-hidden="true"></span>
  Launch faster
</h1>

Props

Icon.astro reicht seine Props an toSvg weiter und akzeptiert daher die gemeinsamen Optionen mit ihren camelCase-Namen, dazu class und style als Strings für das svg-Element. Anders als beim Core-Renderer kann morphTo hier ein Name sein, weil toSvg ihn auflöst.

OptionTypStandardBeschreibung
sizenumber, string24Breite und Höhe; Zahlen sind Pixel.
colorstringcurrentColorHauptfarbe.
secondaryColorstringcolorFarbe der Duotone-Ebene und der Solid-Füllung.
secondaryOpacitynumber0.3 / 1Deckkraft der Duotone-Ebene oder der Solid-Füllung.
weightnumber2Strichstärke von 1 bis 3 im 24er-Raster, unter 24 px optisch ausgeglichen.
absoluteWeightbooleanfalseHält den Strich bei jeder Größe auf weight Pixeln.
cornersround, sharproundAbgerundete oder spitze Verbindungen und Enden.
variantoutline, duotone, solidoutlineStilachse; solid entsteht aus den geschlossenen Formen.
rotatenumber0Drehung in Grad.
flipXbooleanfalseHorizontal spiegeln.
flipYbooleanfalseVertikal spiegeln.
mirrorRtlbooleanfalseIn Layouts von rechts nach links spiegeln.
animatedraw, pop, wiggle, spin, pulse, bounce, shakekeinerVoreinstellung für den lebendigen Zustand.
triggermount, hover, click, statemountWann die Animation oder der Morph abläuft.
activebooleanfalseDer Zustand für den Auslöser state.
durationnumber (ms)je nach VoreinstellungDauer der Animation oder des Morphs.
delaynumber (ms)0Verzögerung der Animation oder des Morphs.
loopboolean, numberfalseEndlos oder eine bestimmte Anzahl von Malen wiederholen (spin und pulse laufen standardmäßig in Schleife).
modifierplus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dotkeinerBadge mit automatischer Aussparung.
modifierCornertop-left, top-right, bottom-left, bottom-rightbottom-rightEcke des Badges.
morphToname, datakeinerZiel des Morphs; der Auslöser bestimmt, wann es erscheint.
titlestringkeinerZugänglicher Name: title, role img und aria-label.
decorativebooleantrue ohne titleVerbirgt das Icon vor assistiven Technologien.

Stolperfallen

Scoped Styles und set:html
Regeln im Style-Block einer Komponente greifen nicht bei Markup, das mit set:html eingefügt wurde, weil ihm die Scoping-Attribute fehlen. Verwenden Sie :global(.glyphfox) innerhalb eines gescopten Selektors, oder lassen Sie color vererben.
Namen in Islands
MorphIcon, Icon und morphTo laden Namen bei Bedarf nach. Registrieren Sie deren Daten mit registerIcons, damit das Server-HTML vollständig ist.
Klick-Auslöser in Buttons
trigger="click" auf glyph-fox lauscht auf dem Icon selbst, und Klicks auf das Padding des Buttons erreichen es nicht. Verwenden Sie trigger="state" und setzen Sie active vom Button aus.
Unbekannte Namen stoppen den Build
toSvg wirft bei einem nicht existierenden Namen einen Fehler, der einen statischen Build abbrechen lässt und im Servermodus eine Fehlerantwort liefert. Gleichen Sie Namen aus Inhalten mit der Icon-Liste ab, oder fangen Sie den Fehler ab, wenn die Namen aus Benutzerdaten stammen.
Server-Bundles auf Edge-Runtimes
toSvg aus dem Haupteinstiegspunkt packt alle Icons ins Server-Bundle, etwa 154 KB minifiziert. Wo die Funktionsgröße begrenzt ist, verwenden Sie renderToString aus glyphfox/core mit Importen pro Icon und übergeben Icon-Daten an morphTo.
Wrapper und Hover-Morphs
Ein Hover-Morph reagiert auf das svg-Element und auf sein direktes Elternelement. Wenn Sie das Icon in ein zusätzliches Element einpacken, wird dieses Element zum Elternelement, und ein Hover über den umgebenden Link startet den Morph nicht mehr.

Häufige Fragen

Liefern im Frontmatter gerenderte Icons JavaScript aus?

Nein. Das Frontmatter läuft auf dem Server oder zur Build-Zeit, und die Seite erhält reines SVG. Presets und Hover-Morphs sind CSS innerhalb dieses SVG. Nur Islands und das Custom Element bringen Client-Code mit.

Kann ich Icons in Markdown- oder MDX-Inhalten verwenden?

Importieren Sie in MDX Icon.astro und verwenden Sie es wie in jeder Komponente. Reines Markdown kann keine Komponenten importieren. Rendern Sie die Icons dort im Layout um den Inhalt herum, oder verwenden Sie die Tailwind-Klassen in rohem HTML, sofern Ihr Markdown das zulässt.

Icons in diesem Leitfaden