Skip to content

Icons

Lattice renders icons from a single SVG sprite built at your app’s Vite step. Components reference an icon by name (a string that comes from the server), and the sprite resolves it at render time — so adding an icon is just dropping an SVG in a folder, with no per-icon imports.

The sprite is produced by Lattice’s Vite helper, which wraps @lattice-php/vite-svg-sprite and merges Lattice’s built-in icons with your own into one cached file.

Add Lattice’s helper to vite.config.ts. The helper includes Lattice’s icons automatically. Later directories win on name collisions, so resources/icons can override a built-in icon.

import { lattice } from "@lattice-php/lattice/vite";
export default defineConfig({
plugins: [
lattice({
icons: {
dirs: ["resources/icons"],
},
}),
laravel({
/* ... */
}),
// ...
],
});

Then pass the sprite into Lattice’s Provider:

/// <reference types="@lattice-php/lattice/svg-sprite-client" />
import sprite from "virtual:svg-sprite";
import { Provider, registry } from "@lattice-php/lattice";
createInertiaApp({
setup({ el, App, props }) {
createRoot(el).render(
<Provider registry={registry} sprite={sprite}>
<App {...props} />
</Provider>,
);
},
});

In production the sprite is emitted as a hashed asset and referenced with <use href>; in dev it’s inlined into the page, so it works regardless of where the page is served from.

Drop any SVG into a folder the plugin scans (e.g. resources/icons/spark.svg) and reference it by its filename:

MenuItem::make('Spark')->icon('spark');

Icons inherit their colour via currentColor and their size via the size-* utility on the element, so a single SVG adapts to wherever it’s used. To pull icons from a package instead of downloading them by hand, vendor them.

Rather than hand-download SVGs, you can vendor a named set from an icon package: the plugin copies just the icons you list into your project and commits them. You ship only the icons you use — not a whole library — and the set is reproducible from the config. This is how Lattice sources its own icons from lucide-static.

Install the source package as a dev dependency:

Terminal window
npm install -D lucide-static

Then list the icons you want under include:

lattice({
icons: {
dirs: ["resources/icons"],
include: [
{
from: "lucide-static/icons", // a package's icon folder, or any local directory
names: ["rocket", "sparkles", "wand-sparkles"],
outDir: "resources/icons/lucide",
},
],
},
});

Each build copies rocket.svg, sparkles.svg, and wand-sparkles.svg out of the package into resources/icons/lucide and folds them into the sprite. Reference them by name like any other icon:

MenuItem::make('Launch')->icon('rocket');
  • from — a folder of SVGs: a package’s icon directory resolved from node_modules (e.g. lucide-static/icons), or a path to a local directory.
  • names — the filenames to copy, without .svg. A name missing from the source fails the build, so a typo surfaces immediately.
  • outDir — where the SVGs are written. It joins the sprite automatically; you don’t also list it under dirs.

The copy is idempotent: it writes only files whose content changed, so re-running the build is a no-op once synced, and it never touches anything else in the folder — vendored and hand-authored icons can share a directory. Commit the copied SVGs; the source package is then only needed at build time, so anyone installing your package gets the icons without it.

Anywhere a component takes an icon you can pass a plain string or a backed enum:

use Lattice\Lattice\Core\Enums\Icon;
// by name
Action::make('app.send')->icon('send');
// or via the curated enum of Lattice's built-in icons
Action::make('app.send')->icon(Icon::Send);

Lattice\Lattice\Core\Enums\Icon covers Lattice’s own icon set. For your full set (Lattice’s plus your own), generate an enum — see below.

Icon is also a component, so a standalone icon can go anywhere in a schema. It renders through the same renderer as ->icon(), with structured size/color plus a raw class escape hatch:

use Lattice\Lattice\Core\Components\Icon;
use Lattice\Lattice\Core\Enums\Color;
use Lattice\Lattice\Core\Enums\Size;
Stack::make()->schema([
Icon::make('house'), // size defaults to Md
Icon::make('circle-check')->size(Size::Lg)->color(Color::Success),
Icon::make('spark')->class('opacity-70'),
]);

size defaults to Size::Md; color is optional and inherits currentColor when unset. Sizes resolve to themeable tokens (--lt-icon-xs--lt-icon-xl).

The plugin can generate a type module and/or a PHP enum from the built sprite, so icon names stay autocompletable. Both files are committed and regenerated idempotently on each build.

TypeScript — Lattice emits resources/js/types/sprite-icons.ts by default. Override dts when you want a different generated file:

lattice({
icons: {
dirs: ["resources/icons"],
dts: {
file: "resources/js/sprite-icons.ts",
augmentModule: "@lattice-php/lattice",
augmentInterface: "KnownIcons",
},
},
});

PHPphpEnum emits a backed enum covering your full sprite:

lattice({
icons: {
dirs: ["resources/icons"],
phpEnum: { file: "app/Support/Icon.php", namespace: "App\\Support", enum: "Icon" },
},
});
use App\Support\Icon;
MenuItem::make('Home')->icon(Icon::House);

Re-run the build (or dev server) after adding icons to refresh the generated files.

Server-driven icons resolve through a stack of renderer functions, so you can override how a name renders — for example to pull from an icon-component library — by wrapping part of the tree in IconRendererProvider:

import { IconRendererProvider } from "@lattice-php/lattice";
<IconRendererProvider renderer={({ icon, className }) => /* a node, or null to fall through */}>
<App />
</IconRendererProvider>;

A renderer that returns null falls through to the next one, ending at the sprite. This is rarely needed — dropping an SVG in a folder is the usual path.