Iconography
How icons work in Marigold and the catalog of available icons.
Icons in Marigold are built on Lucide, with a small set of brand-specific icons added on top. The Principles and Catalog sections cover the design language. Jump to Using icons in code for installation and the API.
Principles
Visual language and sizing
Icons follow Lucide's grid: 24×24, 2px stroke, rounded corners. Brand icons
match the same grid so they sit alongside Lucide icons without standing out.
Recommended sizes are 16, 20, 24, and 48 pixels. Use 20 for dense desktop
layouts, 24 as the default body size, and 48 for display headings. Set the
size with the size prop, which accepts a number of pixels.
Touch targets
Icons by themselves are not large enough to act as tap targets. Wrap an
interactive icon in a Button with size="icon", or another container
with a hit area of at least 48×48 px (Marigold target, WCAG 2.5.5 requires a
44×44 minimum). Don't enlarge the icon to meet the target. Keep the icon at
its content size and pad the surrounding control.
Color and pairing with text
Icons inherit their color from the surrounding text, so set a text-* token
on the parent rather than passing a raw hex value or the Lucide color prop.
Three contexts cover almost every placement:
- Alongside body text. The icon picks up
text-foreground(ortext-secondaryfor help text) automatically. - Inside a colored container like a primary or destructive button. Apply
the paired
-foregroundtoken to the container. The icon follows. - Status icons in Toast, SectionMessage, or a badge. Use the
-accentvariant of the status token (text-destructive-accent,text-warning-accent,text-success-accent,text-info-accent).
When an icon sits next to a label, align it to the cap-height baseline and use
the tight (6px) or related (8px) spacing token for the gap. See
Token Overview for the full list of pairings.
Decorative versus meaningful
Icons paired with a visible label are decorative. Mark them aria-hidden so
assistive technology doesn't repeat the label. Icon-only interactive elements
need an aria-label (or a visually hidden text label) that describes the
action, not the icon.
Catalog
Click an icon to copy its <svg> to the clipboard. To use it from code, see
Using icons in code below.
UI
Info
Action
Ticketing
User
Social
Using icons in code
This section is the engineering reference. For the design rationale behind sizing, color, and accessibility, see Principles above.
Installation
Marigold icons are distributed as @marigold/icons:
# with npm
npm install @marigold/icons --save
# with pnpm
pnpm add @marigold/iconsThe package is tree-shakeable (sideEffects: false), so named imports do not
pull the full Lucide bundle. Peer dependency: react: >=19.0.0.
Importing
Import icons by name from @marigold/icons:
import { DesignTicket, Search } from '@marigold/icons';
export const MyComponent = () => (
<>
<Search />
<DesignTicket />
</>
);@marigold/icons re-exports every icon from lucide-react, so any name listed
on lucide.dev resolves under @marigold/icons. Always
import from @marigold/icons, never directly from lucide-react.
Sizing
size is a number of pixels (default 24). Use the recommended sizes from
Visual language and sizing above.
Color
currentColor and className (recommended)
Icons inherit currentColor, so apply theme tokens via className="text-*"
on the icon or its parent. Both forms below render identically, but
className is the token-aware pattern.
import { Inline, Stack, Text } from '@marigold/components';import { TriangleAlert } from '@marigold/icons';export default () => ( <Stack space={4}> <Inline space={2} alignY="center"> <TriangleAlert color="var(--color-destructive-accent)" /> <Text>Using the color prop</Text> </Inline> <Text color="destructive-accent"> <Inline space={2} alignY="center"> <TriangleAlert /> Inherits currentColor from the parent </Inline> </Text> <Inline space={2} alignY="center"> <TriangleAlert className="text-destructive-accent" /> <Text>className applied directly to the icon</Text> </Inline> </Stack>);The color prop
The color prop is a literal CSS color string and maps to the stroke SVG
attribute. Theme token names like "warning" will not resolve.
// Won't work — "destructive-accent" is not a CSS color
<TriangleAlert color="destructive-accent" />
// Works — literal CSS variable reference
<TriangleAlert color="var(--color-destructive-accent)" />
// Recommended — className with a theme token
<TriangleAlert className="text-destructive-accent" />See Token Overview for token names.
Filled brand icons
Some brand icons are solid shapes instead of outlines. For these, setting
fill (or color) colors the entire icon at once.
import { Inline, Stack, Text } from '@marigold/components';import { DesignTicket } from '@marigold/icons';export default () => ( <Inline space={8} alignY="top"> <Stack space={2} alignX="center"> <DesignTicket size={32} /> <Text size="sm">Default (currentColor)</Text> </Stack> <Stack space={2} alignX="center"> <DesignTicket size={32} fill="var(--color-destructive-accent)" /> <Text size="sm">fill colors the whole icon</Text> </Stack> </Inline>);Accessibility
Icons get aria-hidden="true" automatically when no aria-* prop is passed.
Pass aria-label for icon-only interactive elements to opt out.
// Decorative (paired with visible text) — nothing extra needed
<span><Trash2 /> Delete</span>
// Meaningful (icon-only) — provide aria-label
<button aria-label="Delete"><Trash2 /></button>For tap-target rules, see Touch targets above.