CLI that bundles a project's SVG icons into a single sprite and generates the matching TypeScript definitions that power @uxf/ui's <Icon> component.
Use it in any UXF web project that renders icons through @uxf/ui/icon. From a declarative config (icons.config.js) of inline SVGs and/or Font Awesome Pro references it produces an SVG sprite, one standalone SVG per icon, and a generated icons.ts that:
ICONS (per-icon { w, h } map) and ICONS_VERSION (md5 of the sprite), and@uxf/ui/icon/theme's IconsSet interface, so IconName (keyof IconsSet) autocompletes every icon you declared.This is a build-time dev tool run via the icons-gen binary. The runtime <Icon> component itself lives in @uxf/ui/icon, not here.
yarn add -D @uxf/icons-generator
Requires Node >= 24. Peer dependency: @uxf/core (11.114.0). To use the Font Awesome Pro adapter, additionally install the per-style FA packages you reference (see Providers).
Create icons.config.js in your project root:
/** @type {import('@uxf/icons-generator/src/types').IconsConfig} */
module.exports = {
generatedDirectory: "/public/icons-generated/",
icons: {
flame: {
width: 43,
height: 48,
data: `<path fill="#fff" d="M30.84 20.51a1.51 1.51 0 0 0-1.16-.71..." />`,
},
},
};
Run the generator:
icons-gen
Wire the generated ICONS + sprite into @uxf/ui and render icons (see Integration).
icons-gen [options]
| Flag | Alias | Default | Description |
|---|---|---|---|
--configFile |
-c |
icons.config.js |
Path to the config file, resolved from cwd. |
--help |
-h |
— | Print help and exit. |
icons-gen --configFile=custom.icons.config.js
The config file exports an IconsConfig object via module.exports.
| Key | Type | Default | Required | Description |
|---|---|---|---|---|
icons |
Partial<Record<string, SimpleIcon | SizedIcon | IconFromProviderFunction>> |
— | Yes | Icons to generate, keyed by icon name (see Icon types). |
generatedDirectory |
string |
"/public/icons-generated/" |
No | Output dir (relative to cwd) for the sprite and standalone SVG files. Must start/end with /. |
configDirectory |
string |
"/src/config/" |
No | Output dir (relative to cwd) for the generated icons.ts and provider fallbacks. Must start/end with /. |
spriteFileName |
string |
"_icon-sprite.svg" |
No | Sprite file name written into generatedDirectory. |
typeName |
string |
"IconsSet" |
No | Name of the keyof typeof ICONS type exported by the generated file. |
typescript |
boolean |
true |
No | Emit icons.ts vs icons.js. See Gotchas. |
moduleDefinition |
ModuleDefinition | false |
augments @uxf/ui/icon/theme (see below) |
No | Controls the declare module type augmentation; false disables it. |
customDefinitionContent |
string |
— | No | Extra content appended verbatim to the end of the generated definition file. |
A single-size icon.
type SimpleIcon = {
data: string;
height: number;
width: number;
};
flame: {
width: 43,
height: 48,
data: `<path fill="#fff" d="M30.84 20.51a1.51 1.51 0 0 0-1.16-.71..." />`,
}
Different SVG data per pixel size. Each size produces its own sprite symbol (icon-sprite--<name>_<size>) and standalone file (<name>_<size>.svg).
type SizedIcon = Record<number, string>;
logo: {
24: `<path fill="#fff" d="..." />`,
48: `<path fill="#fff" d="..." />`,
}
A function that resolves an icon from a provider (e.g. faPro.icon(...)). See Providers.
type IconFromProviderFunction = (config: _IconsConfig) => { width: number; height: number; path: string };
moduleDefinition)type ModuleDefinition = {
moduleName: string;
typeName: string;
format: "type" | "interface";
};
Defaults to { moduleName: "@uxf/ui/icon/theme", typeName: "IconsSet", format: "interface" }. With these defaults the generated file emits:
declare module "@uxf/ui/icon/theme" {
interface IconsSet {
"flame": true;
// ...one line per icon
}
}
This augmentation is what makes @uxf/ui/icon's IconName (keyof IconsSet) aware of your icons. Set moduleDefinition: false to skip it.
The faPro adapter reads icon data from the per-style Font Awesome packages. Install only the styles you actually use.
| Namespace | Package |
|---|---|
brands.* |
@fortawesome/free-brands-svg-icons |
regular.* |
@fortawesome/pro-regular-svg-icons |
solid.* |
@fortawesome/pro-solid-svg-icons |
light.* |
@fortawesome/pro-light-svg-icons |
thin.* |
@fortawesome/pro-thin-svg-icons |
duotone.* |
@fortawesome/pro-duotone-svg-icons |
duotone-regular.* |
@fortawesome/duotone-regular-svg-icons |
duotone-light.* |
@fortawesome/duotone-light-svg-icons |
duotone-thin.* |
@fortawesome/duotone-thin-svg-icons |
sharp-regular.* |
@fortawesome/sharp-regular-svg-icons |
sharp-solid.* |
@fortawesome/sharp-solid-svg-icons |
sharp-light.* |
@fortawesome/sharp-light-svg-icons |
sharp-thin.* |
@fortawesome/sharp-thin-svg-icons |
sharp-duotone-regular.* |
@fortawesome/sharp-duotone-regular-svg-icons |
sharp-duotone-solid.* |
@fortawesome/sharp-duotone-solid-svg-icons |
sharp-duotone-light.* |
@fortawesome/sharp-duotone-light-svg-icons |
sharp-duotone-thin.* |
@fortawesome/sharp-duotone-thin-svg-icons |
An icon is referenced as "<namespace>.<kebab-icon-name>" (e.g. "regular.calendar-check"). The legacy @fortawesome/fontawesome-pro monolith is no longer supported — the adapter throws if it is installed, so uninstall it.
# Set registry and token
npm config set "@fortawesome:registry" https://npm.fontawesome.com/
npm config set "//npm.fontawesome.com/:_authToken" YOUR_TOKEN
# Install only the styles you use
npm install --save-dev @fortawesome/pro-regular-svg-icons @fortawesome/free-brands-svg-icons
const { faPro } = require("@uxf/icons-generator/src/providers/fa-pro");
module.exports = {
generatedDirectory: "/public/icons-generated/",
icons: {
// keeps the default name, e.g. "faPro_brands.linkedin"
...faPro.adapter(["brands.linkedin"]),
// or assign a custom name
twitter: faPro.icon("brands.twitter"),
},
};
faPro.adapter([...]) names each icon faPro_<namespace>.<name>, while faPro.icon(...) lets you assign a custom key.
If your project already has generated icons, the Font Awesome Pro packages are not required to rebuild them. On each successful resolve the adapter caches the icon into <configDirectory>/icons-fallbacks/faPro.json; when a package is missing, it reads from that fallback file instead. Existing icons keep working, but adding new provider icons still requires the corresponding FA package installed.
Running icons-gen (re)writes:
<generatedDirectory>/<spriteFileName> — the SVG sprite: one <symbol id="icon-sprite--<name>"> per icon (sized icons: icon-sprite--<name>_<size>).<generatedDirectory>/<name>.svg — one standalone SVG per icon (sized: <name>_<size>.svg). SVGs for icons removed from the config are cleaned up on the next run.<configDirectory>/icons.ts — the definition file (see below).<configDirectory>/icons-fallbacks/<provider>.json — cached provider icon data (e.g. faPro.json).The definition file exports:
// this file is generated automatically, do not change anything manually in the contents of this file
export const ICONS_VERSION = "<md5 of the sprite file>";
export const ICONS = {
"flame": { w: 43, h: 48 },
"logo": [24, 48],
// ...
} as const;
export type IconsSet = keyof typeof ICONS; // name comes from `typeName`
declare module "@uxf/ui/icon/theme" { // omitted when moduleDefinition: false
interface IconsSet {
"flame": true;
// ...
}
}
@uxf/ui/iconRun icons-gen (wire it into a gen/prebuild script).
Pass the generated ICONS and sprite path to @uxf/ui's UiContextProvider. Because generatedDirectory lives under public/, the browser URL drops that segment (/public/icons-generated/… → /icons-generated/…):
import { UiContextProvider, UiContextType } from "@uxf/ui/context";
import { ICONS, ICONS_VERSION } from "@/config/icons";
const uiConfig: UiContextType = {
icon: {
iconsConfig: ICONS,
spriteFilePath: `/icons-generated/_icon-sprite.svg?v=${ICONS_VERSION}`,
},
// ...other UI context options (colorScheme, localeConfig, rasterImage, translationFn)
};
Render icons via @uxf/ui's <Icon>. The name prop autocompletes every generated icon thanks to the module augmentation:
import { Icon } from "@uxf/ui/icon";
<Icon name="flame" size={24} />;
(Optional) Preload the sprite:
<link as="image" href={`/icons-generated/_icon-sprite.svg?v=${ICONS_VERSION}`} rel="preload" type="image/svg+xml" />
<Icon> runtime component is @uxf/ui/icon; this package just generates the sprite and types.cwd-relative and need slashes. configDirectory and generatedDirectory are joined onto process.cwd(), so both must start and end with /.typescript: false currently has no effect. The generator always emits icons.ts — the flag falls back to true internally.faPro provider is a deep import: @uxf/icons-generator/src/providers/fa-pro (the published files preserve the src/ layout). The IconsConfig type is at @uxf/icons-generator/src/types.moduleName (@uxf/ui/icon/theme) unless you intentionally augment a different module; changing it breaks the @uxf/ui IconName inference.@uxf/ui/icon (the <Icon> component and IconsSet/IconName types).