The framework's structural icons are drawn with a single masked primitive,
.pa-icon, so every glyph inherits the current text colour, scales
with font size, and is themeable from one place. This page lists the icons
that ship as variables and explains the hover-to-fill affordance.
The masked icon primitive
Each icon is a <span class="pa-icon pa-icon--name">.
The glyph is an SVG mask; the box is painted in
currentColor and shows through it. That means an icon
automatically matches its surrounding text colour and scales with
font-size (default 1em, override with
--pa-icon-size).
Same class,
sized with --pa-icon-size and coloured with
color / currentColor.
Icon variables
These structural affordances ship as icon variables. Add the modifier
class to a .pa-icon span; each modifier points
--pa-icon-src at the matching --pa-icon-name
token.
Close / clear / remove
--x--clear--removeDisclosure & direction
The four chevron directions are one glyph rotated with a transform, so overriding the chevron re-skins all four at once. Same for the ellipsis (horizontal / vertical).
--chevron--chevron-up--chevron-right--chevron-down--chevron-left--caret-up--caret-down--expand--collapseActions
--add--edit--delete--save--copy--downloadUtility
--search--refresh--filter--check--ellipsis--ellipsis-vertical--link--external-link--settings--bell--user--favoritesSeverity
One shared family used by toasts, alerts, callouts, notifications and popconfirm, so every severity surface shows the same mark. Shown here in their semantic colours.
--info--success--warning--dangerHow the tokens re-skin
Most icons trace through a shared, cross-ecosystem contract, so a single override re-skins Pure Admin, the pure-css shell and the KeenMate web components together:
.pa-icon--search → var(--pa-icon-src)
→ var(--pa-icon-search)
→ var(--base-icon-search, inline Lucide fallback)
--base-icon-*— the shared contract (published in@keenmate/base-css-variablesand mirrored by@keenmate/pure-css). Override once to re-skin everything.--pa-icon-*— Pure Admin's family; falls back to an inline Lucide glyph so icons always render even without the contract loaded.- pa-only glyphs — a few (e.g.
--pa-icon-favorites) are Pure Admin-only and are not part of the--base-*contract, so they're defined directly with no--base-icon-*route.
To retarget a single glyph, set its --pa-icon-name
(or the shared --base-icon-name) at
:root or on any subtree.
Hover-to-fill (enabled buttons & tabs)
An icon can swap to a filled variant when its enabled button or tab is hovered. It's opt-in on two axes:
- Per glyph — an icon opts in by declaring a filled
source on
--pa-icon-src-hover. Icons without one are left untouched. - Per context — the swap only fires inside an
enabled
.pa-btnor.pa-tabs__itemon:hover. Disabled controls never react.
The default Lucide set is outline-only
Lucide ships no filled glyphs, so hover-to-fill is
dormant out of the box — the mechanism is
present but there's nothing to fill to. To activate it, point
--pa-icon-src-hover at a filled glyph from a set
that has one — Tabler (a Lucide look-alike),
Fluent, or Material. The live demo below uses a Tabler
regular/filled star pair.
Live demo
Hover each control. The first uses a
Tabler outline→filled star and morphs; the second is a Lucide star and
stays outline (nothing to fill to); the third is the same
Tabler star but disabled, so it never reacts despite being fillable
(proving the disabled gate). No transition —
mask-image can't tween, so the fill is an instant swap.
How to enable it
Define a modifier that declares both a resting (outline) and a hover (filled) source. The framework's global rule swaps them on hover:
/* your glyph — resting outline + filled-on-hover source */
.pa-icon--star {
--pa-icon-src: var(--pa-icon-star); /* Lucide outline */
--pa-icon-src-hover: url("…tabler filled star…"); /* filled variant */
}
/* framework rule (ships in core) — no-op unless a glyph declared a hover src.
Sets mask-image directly (not --pa-icon-src) so the var(--pa-icon-src)
fallback isn't self-referential — a custom-property cycle would blank the
mask and leave a solid box. */
.pa-btn:not(:disabled):hover .pa-icon,
.pa-tabs__item:not(:disabled):hover .pa-icon {
mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
}
The fallback to
--pa-icon-src is what makes the rule safe to ship
globally: any icon that didn't declare a filled source simply keeps its
resting glyph.