Smart icons

Icons that show data, follow the reader and report status

Battery, signal, wifi, volume, progress, thermometer, calendar, clock, file and badge icons drawn from a value, a date or a count. A currency sign that comes from the locale, arrows that turn around in right to left layouts and lines that get heavier when the reader asks for more contrast. A status icon that morphs from loading to done, and groups that animate in a wave.

Data icons

Every data icon is drawn on the same 24 grid, with the same stroke, caps and padding as the rest of the set, so size, color, weight, corners, variant, animate and title work as usual. The value runs from 0 to 1. A value above 1 without a max is read as a percentage, and min with max map real values, such as a temperature.

Status.jsx
import { SmartIcon } from 'glyphfox/react';

export function DeviceStatus({ battery, charging, signal, volume, upload }) {
  return (
    <>
      <SmartIcon kind="battery" value={battery} charging={charging} title="auto" />
      <SmartIcon kind="signal" value={signal} max={4} />
      <SmartIcon kind="wifi" value={0.66} />
      <SmartIcon kind="volume" value={volume} muted={volume === 0} />
      <SmartIcon kind="progress" value={upload} label />
      <SmartIcon kind="thermometer" value={21.5} min={-10} max={40} unit="°C" />
    </>
  );
}

Each icon carries classes for its state (gf-low, gf-full, gf-charging, gf-muted, gf-hot, gf-cold), and unlit bars and arcs carry gf-off, so a stylesheet can color them. title="auto" gives the icon an accessible name that describes the data, such as "Battery 64%", with numbers formatted for the locale.

Calendar and clock

The calendar shows today by default, or the date you pass (a Date, a timestamp or "2026-10-23"), with the digits of the locale. The clock shows the current time, or a given time ("09:30", "18:45:10" or a Date); seconds adds the second hand. With tick, the clock and the calendar follow the real time, updating once per second, per minute or at midnight.

index.html
<glyph-fox-smart kind="calendar" tick></glyph-fox-smart>
<glyph-fox-smart kind="calendar" date="2026-12-25" locale="ar-EG"></glyph-fox-smart>
<glyph-fox-smart kind="clock" tick seconds></glyph-fox-smart>
<glyph-fox-smart kind="clock" time="09:30"></glyph-fox-smart>

Files and badges

The file icon prints its extension (up to four letters) from ext or a filename. The badge puts a notification count on the bell, or on any icon given as icon, with the same knockout gap the modifiers use. Counts above max (99) read "99+", 0 hides the bubble and dot shows a dot. badgeColor colors the bubble; the number is cut out of it, so it reads on any background.

Count 3
Inbox.vue
<script setup>
import { SmartIcon } from 'glyphfox/vue';
defineProps({ unread: Number, file: String });
</script>

<template>
  <SmartIcon kind="badge" :count="unread" badge-color="#e5484d" />
  <SmartIcon kind="badge" icon="mail" :count="unread" :max="9" />
  <SmartIcon kind="file" :filename="file" :size="32" />
</template>

Currency

kind="currency" picks its sign from the locale: the region gives the currency and Intl.NumberFormat gives its symbol, which is drawn as R$, the euro, the yen (also for the yuan), the pound, the dollar (also for pesos and other dollars) or the generic currency sign. Pass currency="EUR" to choose the currency yourself. Without a locale, the icon uses the language of the document, then the language of the browser.

Price.svelte
<script>
  import { SmartIcon } from 'glyphfox/svelte';
  let { locale } = $props();
</script>

<SmartIcon kind="currency" {locale} title="auto" />
<SmartIcon kind="currency" currency="JPY" />

Right to left

Directional icons (arrows, chevrons, undo and redo, reply, send, log in and out, lists, indent) now mirror by themselves in right to left layouts, in every package: they carry the gf-rtl class and a rule that flips them under dir="rtl". With a locale or dir prop the decision follows that locale instead of the page, so an Arabic widget in an English page still points the right way. mirrorRtl={false} turns it off, and registerDirectional(['my-arrow']) adds your own icons. Media controls such as play and fast forward never mirror.

Pager.jsx
import { ChevronRightIcon, SmartIcon } from 'glyphfox/react';

// Follows the page: points left inside dir="rtl".
<ChevronRightIcon />

// Follows a locale, whatever the page direction.
<SmartIcon name="chevron-right" locale="ar" />

    More contrast

    When the reader asks for more contrast (prefers-contrast: more), smart icons draw their lines half a weight step heavier, set their labels bolder and raise the unlit parts. The rule travels inside the SVG, so it also works in server rendered markup and in exported files. contrast="more" applies the bump all the time and contrast="off" never does.

    StatusIcon

    One icon for the four states of a task: idle, loading, success and error. Every change morphs with the glyphfox morph engine (the circle opens into the spinner, the spinner closes around the check), and loading spins once the morph has settled. duration times the morph, spinDuration the spin, and reduced motion jumps straight to the new state.

    SaveButton.jsx
    import { StatusIcon } from 'glyphfox/react';
    
    export function SaveButton({ state, onSave }) {
      return (
        <button onClick={onSave} aria-busy={state === 'loading'}>
          <StatusIcon state={state} title="auto" /> Save
        </button>
      );
    }

    Without JavaScript, statusSvg('success', { from: 'loading' }) returns an SVG that morphs on load with CSS only.

    IconGroup

    A group plays one living state preset across its icons with a stagger between them. Triggers: mount, hover (the whole group), click (replays on every click) and state (plays while active). from="end" or "center" changes the order of the wave. Children that set their own preset or delay keep it; icons renders names, icon data or smart items for you.

    Hover the row below.

    Toolbar.jsx
    import { IconGroup, HomeIcon, SearchIcon, BellIcon } from 'glyphfox/react';
    
    <IconGroup animate="pop" stagger={70}>
      <HomeIcon />
      <SearchIcon />
      <BellIcon animate="shake" />
    </IconGroup>
    
    <IconGroup icons={['home', 'search', { kind: 'battery', value: 0.8 }]} animate="draw" trigger="hover" />

    Every package

    The same three pieces ship in React, Vue and Svelte (SmartIcon, StatusIcon, IconGroup), as custom elements and as plain functions in the core.

    index.html
    <script src="https://cdn.jsdelivr.net/npm/glyphfox@1"></script>
    
    <glyph-fox-smart kind="battery" value="0.4" charging></glyph-fox-smart>
    <glyph-fox-smart kind="currency" locale="pt-BR"></glyph-fox-smart>
    <glyph-fox-smart name="arrow-right" locale="he"></glyph-fox-smart>
    <glyph-fox-status state="loading"></glyph-fox-status>
    <glyph-fox-group animate="pop" stagger="80" trigger="hover">
      <glyph-fox name="home"></glyph-fox>
      <glyph-fox name="search"></glyph-fox>
    </glyph-fox-group>
    server.js
    import { smartSvg, statusSvg, groupSvg, currencyInfo, isRtlLocale } from 'glyphfox';
    
    smartSvg('battery', { value: 0.42, size: 32, title: 'auto' });
    smartSvg('calendar', { date: '2026-10-23', locale: 'pt-BR' });
    smartSvg('badge', { count: 12, icon: 'mail' });
    smartSvg('arrow-right', { locale: 'ar' });          // any icon, mirrored
    statusSvg('success', { from: 'loading' });          // CSS only morph
    groupSvg(['home', 'file', { kind: 'wifi', value: 1 }], { animate: 'pop', stagger: 80 });
    currencyInfo({ locale: 'ja-JP' });                  // { currency: 'JPY', symbol: '¥', glyph: 'yen', ... }
    isRtlLocale('fa-IR');                               // true

    smartIcon(kind, options) returns plain icon data, so a smart icon can also feed renderIcon, a custom renderer or the morph engine. In glyphfox/core the same functions resolve names from the icons you register.

    Options

    On top of every shared prop. Attributes use kebab-case (badge-color).

    OptionKindsDescription
    kindallbattery, signal, wifi, volume, progress, thermometer, calendar, clock, file, badge or currency. Without a kind, name renders any icon with the locale and contrast behaviors.
    value, min, maxbattery, signal, wifi, volume, progress, thermometerThe level: 0 to 1, a percentage, or a real value between min and max.
    chargingbatteryDraws a bolt cut into the level.
    mutedvolumeThe muted speaker (also at value 0).
    labelprogresstrue prints the percentage inside the ring, a string prints up to four characters.
    unitthermometerUnit of the accessible description, such as "°C".
    datecalendarA Date, a timestamp or "YYYY-MM-DD". Default today.
    time, secondsclock"HH:MM", "HH:MM:SS", a Date or { hours, minutes }. Default now. seconds adds the second hand.
    tickclock, calendarFollows the real time (when no time or date is given).
    ext, filenamefileThe extension label, up to four characters.
    count, max, dotbadgeThe count, the largest number shown before "+" (99) and a dot instead of a number.
    icon, badgeColorbadgeThe icon under the bubble (default bell) and the color of the bubble.
    currencycurrencyAn ISO code instead of the currency of the locale.
    locale, dirallSymbols, digits and dates; also decides the mirroring of directional icons.
    contrastallauto (default) follows prefers-contrast: more, more always bumps the weight, off never does.
    title="auto"allAn accessible name that describes the data or the state.
    state, spinDurationStatusIconidle, loading, success or error; the length of one turn of the spin.
    animate, stagger, delay, from, trigger, active, iconsIconGroupThe preset, the delay between icons (60 ms), the first delay, the order of the wave, the trigger, the state and the icons to render.