Icons
Upload, optimize, and render custom SVG icons, organized into reusable icon sets.
Manage your icons as first-class CMS content. Upload SVGs and they're optimized on the way in, group them into named icon sets, and render any icon by name from a server component or inline in your code.
Overview
Icons are SVG files you upload through the Payload admin. On upload, each file is cleaned up and its viewBox is tightened so what's stored is the smallest correct version of the original, with no per-render cost and no manual cleanup. Icons are then grouped into icon sets (e.g. "Social", "Nav"), so a whole set of brand icons can travel with the active design without code changes.
Once stored, an icon can be rendered anywhere by name, dropped into content as a child block, or picked from a select widget in the admin.
How it works
Two collections back the feature:
Icon: an upload collection that accepts SVG files. On upload, theformatSVGHookruns the file throughsvgo(cleanup) andsvg-path-bbox(tightens theviewBox), so the stored asset is always optimized and theviewBoxis correct.IconSet: groups icons under a named bucket. The active design set can reference icon sets, so icons swap with the theme.
Rendering by name. The <Icon name="…" /> server component looks up an icon by name from the active icon set and renders it inline as an <svg>. Resolution happens server-side through this package's cached iconSet and icon getters (in @pro-laico/icons/cache, built on @pro-laico/core's withCache primitive), so revalidating either cache tag invalidates just the rendered <svg>, not the surrounding page. JSX props you pass always win over the SVG source's intrinsic attributes.
Caching and revalidation. Cache revalidation is driven by @pro-laico/core hooks: revalidateCacheCollectionAfterChange runs on save and revalidateCacheOnDelete runs on delete. Because resolution reads from cached getters keyed by tag, editing or deleting an icon or set invalidates only what it touches.
Other surfaces. AtomicIcon is the admin marker glyph for atomic block types, and IconSelect is the admin select field for picking an icon by name from the active set (its options come from the cached getCachedIconOptions getter).
Using it
Uploading icons
In the admin, open the Icon collection and upload an SVG file. The formatSVGHook runs automatically on upload: SVGO strips and cleans the markup (including script tags) and svg-path-bbox tightens the viewBox, so the stored svgString is already optimized.
Building icon sets
Open the IconSet collection and create a named set (for example "Social" or "Nav"), then add icons to it. The active design set can reference icon sets so the right icons follow the active theme, and non-developers can swap icons per design set without touching code.
Rendering icons
In code, render an icon by name from the active set with the <Icon> server component:
import { Icon } from '@pro-laico/icons/Icon'
<Icon name="arrow-right" />
<Icon name="arrow-right" className="size-6 text-primary" />
<Icon name="logo" fallback={myCustomSvgString} />name looks the icon up in the active icon set, className (and any other JSX props) are applied to the rendered <svg> and override the source's intrinsic attributes, and fallback supplies a raw SVG string to render when no matching icon is found.
In content, editors can place icons with the child blocks:
IconChild: picks an icon from theIconcollection.SVGChild: pastes in raw SVG.
Both render through the frontend renderer in @pro-laico/atomic/children.
Configuration
Icons are added by the iconsPlugin, which accepts two additive option bags: iconOptions for the Icon collection and iconSetOptions for the IconSet collection. User-supplied hooks always run after the built-ins, so formatSVGHook and the revalidation hooks always run first.
import { buildConfig } from 'payload'
import { iconsPlugin } from '@pro-laico/icons'
export default buildConfig({
plugins: [
iconsPlugin({
iconSetOptions: {
// Live preview is on by default; pass this only to override the URL builder.
livePreviewUrl: yourPreview,
extraSettingsFields: [
// e.g. a test path relationship
],
},
}),
],
})Both collections accept additive fields and hooks. iconSetOptions also takes extraSettingsFields (compact, in-row fields next to title/active), fields (full-width set-level fields), and iconRowFields (per-icon metadata on each row). Live preview on IconSet edits is wired by default (it falls back to @pro-laico/core's generateLivePreviewPath), so livePreviewUrl is only needed to override that. If you want the atomicHook snapshot behavior on IconSet, attach it explicitly through the additive hooks option.
See the icons plugin for the full option tables and subpath exports.