One icon set, every framework
Every package takes the same props (size, color, weight, corners, variant, animate, modifier, morphTo and the rest) and renders the same SVG. Pick your framework, or follow a recipe for your meta framework.
Packages
Everything ships in the glyphfox package (Angular also has glyphfox-angular). Each framework is an optional peer dependency, used only when you import its entry point. Icon components are tree shakable and every entry point is typed.
| Framework | Import | Renders |
|---|---|---|
| React | glyphfox/react | Client components (marked 'use client'), forwardRef |
| React Server Components | glyphfox/react/server | Hook free Icon and Fusion, zero JavaScript |
| Vue 3 | glyphfox/vue | Components and useMorph |
| Svelte 5 | glyphfox/svelte | .svelte sources and morphStore |
| Angular | glyphfox-angular | Standalone component and registry provider |
| Solid | glyphfox/solid | Components and useMorph, server and client |
| Preact | glyphfox/preact | Components and hooks, no compat layer |
| Qwik | glyphfox/qwik | Lightweight components that resume with no JavaScript |
| Lit | glyphfox/lit | Lit elements (<gf-file>, <gf-glyph>) |
| Astro | glyphfox/astro | .astro components, static SVG |
| React Native | glyphfox/native | react-native-svg components |
| Ember | glyphfox/ember | Helpers for .gjs, .gts and classic templates |
| Web component | glyphfox/web | <glyph-fox>, also from the CDN |
| Tailwind CSS | glyphfox/tailwind | CSS mask classes |
Solid
import { createSignal } from 'solid-js';
import { HomeIcon, HeartIcon, Fusion, MorphIcon } from 'glyphfox/solid';
export function Toolbar() {
const [open, setOpen] = createSignal(false);
return (
<nav>
<HomeIcon size={20} class="nav-icon" />
<HeartIcon animate="pop" trigger="click" variant="duotone" />
<Fusion icons={['cloud', 'lock']} layout="overlap" />
<button onClick={() => setOpen(!open())}>
<MorphIcon name={open() ? 'x' : 'menu'} />
</button>
</nav>
);
}No JSX compiler setup and no special export condition: the same module renders in SolidStart on the server and in the browser. class, style, ref and events pass through to the svg. useMorph(accessor) returns an accessor of icon data that morphs whenever the name changes.
Preact
import { useState } from 'preact/hooks';
import { FileIcon, HeartIcon, MorphIcon } from 'glyphfox/preact';
export function App() {
const [copied, setCopied] = useState(false);
return (
<>
<FileIcon size={20} weight={1.5} modifier="check" class="doc" />
<HeartIcon animate="pop" trigger="click" />
<MorphIcon name={copied ? 'check' : 'copy'} onClick={() => setCopied(true)} />
</>
);
}The same API as React (Icon, Fusion, MorphIcon, useMorph) built on preact and preact/hooks, so it does not pull in preact/compat. On Preact 11 a ref reaches the svg element. Both class and className work.
Qwik
import { component$, useSignal } from '@qwik.dev/core';
import { iconX } from 'glyphfox';
import { BellIcon, HomeIcon, MenuIcon, registerIcons } from 'glyphfox/qwik';
registerIcons([iconX]); // names used only by morphTo, Icon or Fusion
export default component$(() => {
const open = useSignal(false);
return (
<header>
<HomeIcon size={20} class="logo" />
<BellIcon animate="shake" trigger="hover" />
<button onClick$={() => (open.value = !open.value)}>
<MenuIcon morphTo="x" trigger="state" active={open.value} />
</button>
</header>
);
});Built for Qwik 2 (@qwik.dev/core). The icons are lightweight components: they render on the server and resume without downloading anything. Living states and morphTo run on CSS, active switches trigger="state", and trigger="click" uses a tiny inline handler. Names used by Icon, morphTo and Fusion must be registered: icon components register their icon, and registerIcons([iconX]) (or registerIcons(icons) with icons from glyphfox for the whole set) covers names you only write as strings.
Lit
import { LitElement, html } from 'lit';
import { defineIcons, FileIcon, HeartIcon, Icon, Fusion, MorphIcon } from 'glyphfox/lit';
// <gf-file>, <gf-heart>, <gf-glyph>, <gf-fusion> and <gf-morph>
defineIcons([FileIcon, HeartIcon, Icon, Fusion, MorphIcon]);
class AppBar extends LitElement {
static properties = { open: { type: Boolean } };
render() {
return html`
<gf-file size="20" weight="1.5" modifier="check"></gf-file>
<gf-heart animate="pop" trigger="click" secondary-color="#ff7a1a"></gf-heart>
<gf-glyph name="cloud&lock:overlap"></gf-glyph>
<gf-morph .name=${this.open ? 'x' : 'menu'} @click=${() => (this.open = !this.open)}></gf-morph>
`;
}
}
customElements.define('app-bar', AppBar);Nothing is registered on import: defineIcons(list, { prefix }) defines the elements you use ({ prefix: 'my' } gives <my-file>). Attributes are kebab-case (secondary-color, flip-x, morph-to), properties camelCase; the animate attribute is the animatePreset property, because animate() is a method of every element, and animation plays the designed animation as in every package. class and style style the host element. The elements render in shadow DOM and work with @lit-labs/ssr.
Astro
---
import { HomeIcon, BellIcon, Icon, Fusion } from 'glyphfox/astro';
import SearchIcon from 'glyphfox/astro/icons/search';
---
<nav>
<HomeIcon size={20} class:list={['nav-icon', { active: true }]} />
<SearchIcon weight={1.5} />
<BellIcon animate="shake" trigger="hover" />
<Icon name="file+check@tr" variant="duotone" />
<Fusion icons={['cloud', 'lock']} layout="overlap" />
</nav>Components render static SVG on the server and ship no JavaScript. Every icon of the set is available to Icon names, morphTo and Fusion. class (and class:list), style as a string or an object, and any other attribute pass through to the svg. Hover, mount and state triggers run on CSS; trigger="click" uses a tiny inline handler.
React Native
npm install glyphfox react-native-svg
import { HomeIcon, BellIcon, HeartIcon, MorphIcon } from 'glyphfox/native';
export function Tabs({ open, unread }) {
return (
<View style={{ flexDirection: 'row', gap: 16 }}>
<HomeIcon size={28} color="#ff7a1a" />
<BellIcon animate="shake" trigger="state" active={unread > 0} />
<HeartIcon animate="pop" trigger="click" variant="duotone" />
<MorphIcon name={open ? 'x' : 'menu'} style={{ marginLeft: 'auto' }} />
</View>
);
}Components render react-native-svg elements with the same props. There is no CSS on native, so living states are sampled frame by frame from the same presets and morphs are tweened; both follow the reduce motion setting. trigger="click" plays on press and trigger="hover" while pressed. title sets the accessibility label, style and other props reach the Svg, and refs are forwarded. Metro resolves the glyphfox/native export with package exports, on by default since React Native 0.79.
Ember
import { FileIcon, BellIcon, Glyph, Fusion } from 'glyphfox/ember';
<template>
{{FileIcon size=20 weight=1.5 class="toolbar-icon"}}
{{BellIcon animate="shake" trigger="hover"}}
{{Glyph "file+check@tr" variant="duotone"}}
{{Fusion "cloud" "lock" layout="overlap"}}
</template>Plain function helpers (Ember 4.5 and newer), so they need no addon setup and work in .gjs, .gts and classic templates. They return trusted markup: the shared props, class, style and other attributes are named arguments. Names used by Glyph, morphTo and Fusion must be registered: icon helpers register their icon, and registerIcons([iconCloud]) (or registerIcons(icons)) covers the rest. Hover, mount and state triggers run on CSS; trigger="click" uses a tiny inline handler.