Skip to content

Icons in templates

Menus, view tabs and section templates name their icons as Lucide names (ShoppingCart, Users, FileText). In the backend app a React component resolves that string. A server-rendered page has no React, so the same name is drawn by the lucide() template global.

<span class="tile">{{ lucide('ShoppingCart', size=18) }}</span>

It returns an inline <svg>, already marked safe — no |safe needed, and no escaping to undo. It is installed on every module template environment alongside t, image and money, so a theme, an app-store section or a report gets it without importing anything.

argumentdefaultwhat it does
nameLucide icon name. PackageIcon, LucidePackage, package and package-icon all resolve to Package.
size24Width and height in px. The viewBox is always 0 0 24 24, so the drawing scales.
stroke_width1.8Lucide’s own default is 2; 1.8 reads better at small tile sizes.
css_class""Class on the <svg> itself.

Colour comes from CSS, not from an argument

Section titled “Colour comes from CSS, not from an argument”

The icon renders with stroke="currentColor" and no fill, so it takes the colour of whatever it sits inside:

<span class="tile" style="background: {{ app.menu_color }}">
{{ lucide(app.icon, size=18) }}
</span>
.tile { color: #fff; } /* the icon follows */
.tile:hover { color: var(--theme-primary); }

That is deliberate — an icon whose colour is baked into its markup cannot respond to a hover state, a dark mode, or the theme’s palette.

An unknown name renders nothing, not an error

Section titled “An unknown name renders nothing, not an error”

If the name is not a Lucide icon, lucide() returns an empty string. Your container still renders and is simply empty, rather than the page failing over a decoration.

The practical consequence: wrap the call in the element you want to see either way. If the tile is what carries the background and border, put the call inside the tile — not the other way round.

Two things follow from this:

  • A typo renders silently. Validate authored names the same way the view gate does rather than relying on the page to complain.
  • Only the icons this repo references ship with geometry, so a name that is a real Lucide icon but appears nowhere in any module’s YAML has no path data on the server and draws nothing. If you name icons somewhere the scan does not look (a database value, a computed string), reference them once in your module’s YAML so they are included.