Iconography
Bumi uses outlined icons consistently across all platforms. The icon system prioritizes clarity and visual consistency over decoration.
Icon Libraries
| Platform | Library | Source |
|---|---|---|
| Web (all portals) | Lucide React | lucide-react package |
| iOS (mobile apps) | SF Symbols | via expo-symbols |
| Android (mobile apps) | Material Symbols | via expo-symbols |
Common Icons (Lucide, 24px, stroke 2)
Home
ShoppingBag
Package
Users
CreditCard
Settings
Search
Bell
Clock
BarChart
Truck
CheckCircle
AlertTriangle
X
Plus
Download
Size Comparison
16px
18px
20px
24px
32px
Icon Sizes
| Size | px | Usage |
|---|---|---|
| Small | 16px | Sidebar nav icons, inline badges |
| Default | 18px | Inline with text, table row actions |
| Medium | 20px | Buttons (icon + label), form field icons |
| Large | 24px | Feature cards, empty states, tab bar |
| XL | 32px | Page-level feature icons, onboarding |
Stroke Width
| Context | Stroke Width | When |
|---|---|---|
| Small / sidebar | 1.5px | 16px icons in navigation, dense UIs |
| Standard | 2px | 18px+ icons, default for most contexts |
tsx
// Sidebar icon (small, thin stroke)
<Store size={16} strokeWidth={1.5} />
// Button icon (standard stroke)
<Plus size={20} strokeWidth={2} />Color
Icons inherit their color from the parent text via currentColor. This keeps icon color consistent with surrounding text without manual overrides.
css
.icon {
color: currentColor;
}State-Based Opacity
| State | Opacity |
|---|---|
| Active / selected | 1.0 (full color) |
| Default | 0.7 |
| Inactive / disabled | 0.4 |
tsx
// Active nav item
<LayoutDashboard size={16} strokeWidth={1.5} className="opacity-100" />
// Inactive nav item
<LayoutDashboard size={16} strokeWidth={1.5} className="opacity-50" />Custom SVG Icons
Some concepts are not covered by Lucide. For these, use custom SVG icons from the RetailOS illustration library:
| Category | Examples |
|---|---|
| Devices | POS terminal, barcode scanner, receipt printer, EDC machine |
| Payment methods | QRIS logo, e-wallet icons, bank transfer icon |
| Tier badges | Bronze leaf, Silver shield, Gold star, Platinum crown |
| Indonesian-specific | NPWP icon, Indonesian flag indicator |
Custom SVGs follow the same sizing and stroke conventions as Lucide icons.
Naming Convention
icon-{category}-{name}.svg
Examples:
icon-device-pos-terminal.svg
icon-payment-qris.svg
icon-tier-gold.svgUsage Examples
Button with Icon
tsx
import { Plus } from 'lucide-react';
<button className="btn-primary">
<Plus size={20} strokeWidth={2} />
Tambah Produk
</button>Navigation Item
tsx
import { ShoppingCart } from 'lucide-react';
<NavItem
icon={<ShoppingCart size={16} strokeWidth={1.5} />}
label="Penjualan"
active={currentPath === '/sales'}
/>Status with Icon
tsx
import { CheckCircle, AlertCircle } from 'lucide-react';
// Success
<span className="text-success flex items-center gap-2">
<CheckCircle size={18} strokeWidth={2} />
Berhasil
</span>
// Error
<span className="text-danger flex items-center gap-2">
<AlertCircle size={18} strokeWidth={2} />
Gagal
</span>DO and DON'T
DO
- Use outlined (stroke) icons consistently --- never filled
- Set
strokeWidthexplicitly (1.5 for small, 2 for standard) - Use
currentColorso icons inherit the text color - Pair icons with text labels in navigation (icon-only buttons need tooltips)
DON'T
- Don't mix filled and outlined icons in the same context
- Don't use emoji as icons in the UI
- Don't scale icons beyond 32px --- use illustrations instead
- Don't add color to icons independently of their text context (except for semantic status colors)