Foundation
A consistent icon system that provides visual clarity and reinforces meaning across the interface. Users building with the AI agent can choose their icon library; Phosphor is the default.
Marmo UI lets you build with any of several popular MIT-licensed icon libraries. The AI agent asks which library you want to use before generating UI code, and the marmo-ui MCP enforces your choice — review_generated_code rejects icons imported from any library other than the one you selected.
The default icon library is Phosphor Icons (@phosphor-icons/react, MIT). Phosphor ships outline, duotone, and filled variants from a single set via a weight prop, which maps cleanly to the three icon styles the product uses.
Icon wrapper component (@marmoui/ui) provides consistent sizing, alignment, and two-tone color tokens for any library you pick.When you build UI with the AI agent, it asks which library you want. Pass the library id to get_design_guidelines and review_generated_code so the rules and validator match.
| Library | id | Package | License | Weights |
|---|---|---|---|---|
| Phosphor Icons (default) | phosphor | @phosphor-icons/react | MIT | regular · duotone · fill |
| Material Design | material | react-icons/md | MIT | (by name) |
| Lucide | lucide | lucide-react | ISC¹ | outline only |
| Tabler | tabler | @tabler/icons-react | MIT | outline + *Filled |
| Heroicons | heroicons | @heroicons/react | MIT | outline · solid |
| Feather | feather | react-icons/fi | MIT | outline only |
¹ Lucide is ISC-licensed, not MIT. It is included in the picker for convenience, but if your policy requires strict MIT-only, choose one of the other libraries.
The product uses three icon styles. Each library maps to them as follows:
| Style | Phosphor | Material | Heroicons | Lucide / Tabler / Feather |
|---|---|---|---|---|
| outline | weight="regular" (default) | Md… filled set, or MdOutline… | @heroicons/react/24/outline | default |
| duotone | weight="duotone" | (no native duotone) | (no native duotone) | (no native duotone) |
| filled | weight="fill" | Md… filled set | @heroicons/react/24/solid | Tabler *Filled; Lucide/Feather n/a |
Phosphor is the only supported library with a native duotone weight. If your designs rely on duotone icons, keep the default (phosphor).
import { Plus, PencilSimple, Trash, MagnifyingGlass } from '@phosphor-icons/react';
// outline (default)
<Plus />
// duotone — two-tone icons; the Icon wrapper maps the secondary color to --color-<fillSecondary>
<Plus weight="duotone" />
// filled
<Plus weight="fill" />Common icon mappings (Phosphor):
| Action | Icon |
|---|---|
| Add / Create | Plus |
| Edit | PencilSimple |
| Delete | Trash |
| Search | MagnifyingGlass |
| Close | X |
| Check | Check |
| Arrow right | ArrowRight |
| Settings | GearSix |
| User | User |
| Download / Upload | DownloadSimple / UploadSimple |
| More options | DotsThreeVertical / DotsThree |
| Refresh | ArrowsClockwise |
| Info / Warning / Error | Info / Warning / XCircle |
The library's built-in icons follow a consistent weight convention so dashboards, navigation, and chrome each read distinctly. Apply the same convention in your own UI:
| Surface | Weight | Example |
|---|---|---|
| Most icons (chrome, actions, form controls) | regular (default — omit weight) | <GearSix />, <Plus /> |
| Dashboard / analytics / chart tiles | duotone | <SquaresFour weight="duotone" />, <ChartDonut weight="duotone" /> |
| Primary navigation icons | regular | <SquaresFour /> |
| Secondary navigation — default state | regular | <AddressBook /> |
| Secondary navigation — active / hover | fill | <AddressBook weight="fill" /> |
| Solid status glyphs (check, star, circle, avatar) | fill | <Check weight="fill" />, <Star weight="fill" /> |
| Dropdown / select caret | regular | <CaretDown /> |
| Menu toggle | regular | <List /> |
import { SquaresFour, CaretDown, List, AddressBook, Check } from '@phosphor-icons/react';
// Dashboard tile — duotone
<SquaresFour weight="duotone" />
// Dropdown caret + menu toggle — regular (no weight)
<CaretDown />
<List />
// Secondary nav: regular default, filled when active
<AddressBook /> // default
<AddressBook weight="fill" /> // activeThe only custom SVGs in the library are the Marmo brand marks, exported from @marmoui/ui/icons. They are brand assets, not icon-library icons, and are independent of your chosen icon library:
| Mark | Name | Usage |
|---|---|---|
| Marmo mark | MarmoIcon | Square brand glyph |
| Marmo wordmark | MarmoLogoWordmark | Mark + "Marmo" wordmark |
| Step indicator | StepIcon / StepFilledIcon | Stepper completed/active step glyphs |
get_design_guidelines({ iconLibrary }) gives you the canonical name per action for each library.Icon wrapper component for consistent sizing, alignment, and two-tone color support (works with any library).text-icon, text-icon-primary).Icons follow a consistent sizing scale that aligns with the component size system. The Icon wrapper applies these regardless of library:
| Size | Dimensions | Use Case |
|---|---|---|
xs | 12px | Compact elements, inline indicators |
sm | 16px | Small buttons, form fields, table cells |
md | 20px | Default size, most UI contexts |
lg | 24px | Prominent actions, headers |
xl | 32px | Feature highlights, empty states |
Icons use semantic color tokens to ensure proper contrast and meaning:
| Token | CSS Variable | Usage |
|---|---|---|
| Default | --color-icon | Standard icon color |
| Light | --color-icon-light | Subtle, secondary icons |
| Primary | --color-icon-primary | Primary action icons |
| Destructive | --color-icon-destructive | Destructive action icons |
For duotone icons (Phosphor weight="duotone"), the Icon wrapper's fill prop sets the primary layer and fillSecondary sets the secondary layer.
aria-label or aria-hidden="true" on icon elements.aria-hidden="true".When generating UI with the marmo-ui MCP:
phosphor).get_design_guidelines({ iconLibrary: '<your choice>' }) to load that library's import source, icon name map, and weight mapping.review_generated_code({ code, iconLibrary: '<your choice>' }) before returning the code. Imports from any other icon library are reported as errors and must be fixed before the code is returned.