5.8 KiB
title, tags, created
| title | tags | created | |||
|---|---|---|---|---|---|
| Iconography |
|
2026-05-23 |
Iconography
Icons come from Iconify — a unified SVG icon library aggregating 100k+ icons from dozens of icon sets, loaded on-demand.
Important
Per cursor rules (
backend/.cursor/rules/ui-development-standards.mdc), Iconify is the only icon system. Do NOT import from@mui/icons-material,react-icons, or inline SVG files unless you're building a wholly custom illustration.
1. Library
Installed as @iconify/react. Wrapped by frontend/src/components/iconify/:
import { Iconify } from 'src/components/iconify';
<Iconify icon="solar:user-bold" />
<Iconify icon="eva:close-fill" width={20} />
<Iconify icon="mingcute:check-fill" sx={{ color: 'success.main' }} />
Props: icon (required), width (number or string, default 20), sx (any MUI sx), plus standard HTML attributes.
2. Approved icon sets
Per the cursor rules, prefer these prefixes:
| Prefix | Set | Style | Best for |
|---|---|---|---|
solar: |
Solar Icons | Bold / Line / Linear / Outline | Default everywhere — most consistent |
eva: |
Eva Icons | Fill / Outline | Compact UI icons (close, more, plus) |
mingcute: |
MingCute | Fill / Line | Detailed actions |
mdi: |
Material Design Icons | Many variants | Use only when above sets lack the metaphor |
simple-icons: |
Brand logos | Monochrome | Social platforms, third-party brands |
flagpack: |
Country flags | Filled | Language switcher, address country |
Tip
Pick ONE style per set across the app for visual consistency. The default convention is
solar:*-boldfor filled andsolar:*-line-duotonefor accents.
3. Sizing
| Size | Use |
|---|---|
| 16 px | Inline with text (caption, body2) |
| 20 px | Inline with body1, navigation items, buttons (default) |
| 24 px | Standalone action buttons, primary nav |
| 32 px | Empty-state illustrations, large CTAs |
| 48 px+ | Hero illustrations (consider Lottie or react-icons set built for hero use) |
Set via width (icon is always square):
<Iconify icon="solar:bell-bold" width={24} />
4. Color
Color comes from the parent's color CSS property (Iconify renders with fill: currentColor). Use the sx prop:
<Iconify icon="solar:check-circle-bold" sx={{ color: 'success.main' }} />
<Iconify icon="solar:warning-bold" sx={{ color: 'warning.dark' }} />
Never hard-code hex — go through palette tokens.
5. Common icon mappings
A non-exhaustive convention table:
| Action / Concept | Recommended icon |
|---|---|
| Search | solar:magnifer-bold |
| Close | eva:close-fill |
| Add / Create | solar:add-circle-bold or mingcute:add-fill |
| Edit | solar:pen-bold |
| Delete | solar:trash-bin-trash-bold |
| Settings | solar:settings-bold |
| Notifications | solar:bell-bold (badge for unread) |
| User / Profile | solar:user-bold |
| Avatar group | solar:users-group-rounded-bold |
| Shopping cart | solar:cart-bold |
| Filter | solar:filter-bold |
| Sort | solar:sort-bold |
| More menu | eva:more-vertical-fill |
| Back | solar:alt-arrow-left-bold (auto-flips RTL) |
| Forward | solar:alt-arrow-right-bold |
| Up / Down | solar:alt-arrow-up-bold / solar:alt-arrow-down-bold |
| Success | solar:check-circle-bold |
| Warning | solar:danger-bold |
| Error | solar:close-circle-bold |
| Info | solar:info-circle-bold |
| Upload | solar:upload-bold |
| Download | solar:download-bold |
| Copy | solar:copy-bold |
| Eye (show/hide password) | solar:eye-bold / solar:eye-closed-bold |
| Wallet | solar:wallet-money-bold |
| Coin / Token | solar:dollar-bold, mingcute:coin-fill |
| QR code | solar:qr-code-bold |
| Chat | solar:chat-round-bold |
| Send (chat) | solar:plain-bold |
| Attachment | eva:attach-2-fill |
| Calendar | solar:calendar-bold |
| Clock | solar:clock-circle-bold |
| Location | solar:map-point-bold |
| Phone | solar:phone-bold |
solar:letter-bold |
|
| Lock | solar:lock-password-bold |
| Unlock | solar:lock-unlock-bold |
| Star (rating) | solar:star-bold (filled) / solar:star-linear (empty) |
| Hamburger | solar:hamburger-menu-bold |
| Refresh | solar:refresh-bold |
| Logout | solar:logout-3-bold |
6. RTL & direction
Direction-implying icons (chevrons, arrows, swipe) are flipped automatically by stylis-plugin-rtl for arrow-class icons. Semantic icons (play, share, send) should NOT flip — wrap them in:
<Box sx={{ direction: 'ltr' }}>
<Iconify icon="solar:play-bold" />
</Box>
Or use transform: 'scaleX(-1)' on RTL if you specifically need to mirror.
7. Custom SVG (when Iconify is not enough)
Place SVGs in public/assets/icons/ or frontend/src/assets/icons/ and use:
import { SvgColor } from 'src/components/svg-color';
<SvgColor src="/assets/icons/custom-shape.svg" sx={{ color: 'primary.main' }} />
svg-color uses the mask-image technique so a single-color SVG inherits the parent color, matching Iconify behavior.
For multi-color illustrations, ship them as separate files in public/illustrations/ and reference with Next Image.
8. Accessibility
- Icon-only buttons MUST have
aria-label:<IconButton aria-label="close"><Iconify icon="eva:close-fill" /></IconButton> - Icons next to a label are decorative — no aria-label needed.
- Live status icons (loading, success) inside a
aria-live="polite"region announce changes.
9. Performance
- Iconify loads icons on demand from its CDN (or self-hosted if configured).
- Bundle impact is minimal — only the icon component, not the icon data.
- For the most-used set (e.g.,
solar:*), consider pre-loading via@iconify-icons/solarto remove the CDN dependency.
10. Related
- Design System Overview · Components · Colors
- Coding Standards — Iconify rule cited