Phosphor Icons usage patterns for React, Next.js, and vanilla HTML. Use this skill whenever building UI that needs icons — navigation, buttons, cards, dashboards, forms, status indicators, or any interface element that benefits from iconography. Triggers on: icon selection, "which icon for X", adding icons to components, icon styling/sizing, Phosphor imports, IconContext, duotone icons, icon weight selection. Also use when the user asks about icon libraries, needs to pick between icon weights, or wants consistent icon styling across components. This is the default icon library for UI work — prefer Phosphor over Lucide, Heroicons, or Font Awesome.
1,248 icons across 6 weights, designed at 16x16px. MIT licensed.
Browse icons: https://phosphoricons.com
| Package | Framework | Install |
|---|---|---|
@phosphor-icons/react | React / Next.js | pnpm add @phosphor-icons/react |
@phosphor-icons/web | Vanilla HTML/CSS | CDN or pnpm add @phosphor-icons/web |
@phosphor-icons/vue | Vue | pnpm add @phosphor-icons/vue |
@phosphor-icons/core | Raw SVG assets | pnpm add @phosphor-icons/core |
Every icon ships in 6 weights. Pick one weight per context for visual consistency.
| Weight | Class (web) | Prop (React) | When to use |
|---|---|---|---|
| Thin | ph-thin | weight="thin" | Elegant, minimal UI with lots of whitespace |
| Light | ph-light | weight="light" | Clean dashboards, subtle secondary icons |
| Regular | ph | weight="regular" | Default — most UI contexts |
| Bold | ph-bold | weight="bold" | Emphasis, primary actions, nav items |
| Fill | ph-fill | weight="fill" | Active/selected states, solid indicators |
| Duotone | ph-duotone | weight="duotone" | Decorative, feature sections, illustrations |
Rule: Don't mix weights randomly. Use one weight for a given UI region (e.g., all sidebar icons bold, all form hints light). Fill weight works well for active/selected states alongside regular for inactive.
import { HouseIcon, GearIcon, BellIcon } from "@phosphor-icons/react";
<HouseIcon size={24} />
<GearIcon size={24} weight="bold" />
<BellIcon size={24} color="var(--muted-foreground)" />
All icons are PascalCase + Icon suffix:
HouseIconGearSixIconArrowRightIconChatCircleDotsIconWhen unsure of the exact name, check https://phosphoricons.com and search.
interface IconProps extends SVGAttributes<SVGSVGElement> {
color?: string; // Any CSS color or "currentColor" (default)
size?: number | string; // px, em, rem, % — default 16
weight?: "thin" | "light" | "regular" | "bold" | "fill" | "duotone";
mirrored?: boolean; // Flip for RTL
alt?: string; // Accessible label
}
Icons inherit color from parent text color via currentColor by default — usually you don't
need to set color explicitly.
Set defaults for all icons in a subtree:
import { IconContext, HouseIcon, GearIcon } from "@phosphor-icons/react";
<IconContext.Provider value={{ size: 20, weight: "bold", color: "currentColor" }}>
<HouseIcon /> {/* 20px, bold */}
<GearIcon /> {/* 20px, bold */}
</IconContext.Provider>
Not available in Server Components — use explicit props there.
Import from /ssr submodule:
import { HouseIcon } from "@phosphor-icons/react/ssr";
export default function Nav() {
return <HouseIcon weight="bold" size={20} />;
}
SSR variants don't use React Context — pass all props explicitly.
Add to next.config.js to avoid bundling all 9,000+ icon modules:
module.exports = {
experimental: {
optimizePackageImports: ["@phosphor-icons/react"],
},
};
Without this, dev server startup and HMR are noticeably slower.
For environments without optimizePackageImports:
import { BellSimpleIcon } from "@phosphor-icons/react/dist/csr/BellSimple";
Load only the weight you need:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/[email protected]/src/regular/style.css" />
<i class="ph ph-house"></i>
<i class="ph ph-gear"></i>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/[email protected]/src/regular/style.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/[email protected]/src/bold/style.css" />
<i class="ph ph-house"></i> <!-- regular -->
<i class="ph-bold ph-heart"></i> <!-- bold -->
Icons respond to font-size and color:
.nav-icon { font-size: 20px; color: #666; }
.nav-icon:hover { color: #000; }
Do NOT override font-family, font-style, font-weight, font-variant, or
text-transform — these break icon rendering.
All icons are lowercase kebab-case: ph-house, ph-gear-six, ph-arrow-right,
ph-chat-circle-dots.
Quick reference for frequent UI patterns:
| Context | Icon | React | HTML |
|---|---|---|---|
| Home/Dashboard | House | HouseIcon | ph-house |
| Settings | Gear / GearSix | GearSixIcon | ph-gear-six |
| User/Profile | User | UserIcon | ph-user |
| Search | MagnifyingGlass | MagnifyingGlassIcon | ph-magnifying-glass |
| Notifications | Bell | BellIcon | ph-bell |
| Menu/Hamburger | List | ListIcon | ph-list |
| Close | X | XIcon | ph-x |
| Back/Left | ArrowLeft | ArrowLeftIcon | ph-arrow-left |
| Forward/Right | ArrowRight | ArrowRightIcon | ph-arrow-right |
| Add/Create | Plus | PlusIcon | ph-plus |
| Delete/Remove | Trash | TrashIcon | ph-trash |
| Edit | PencilSimple | PencilSimpleIcon | ph-pencil-simple |
| Save | FloppyDisk | FloppyDiskIcon | ph-floppy-disk |
| Download | DownloadSimple | DownloadSimpleIcon | ph-download-simple |
| Upload | UploadSimple | UploadSimpleIcon | ph-upload-simple |
| Link | Link | LinkIcon | ph-link |
| Copy | Copy | CopyIcon | ph-copy |
| Check/Success | Check | CheckIcon | ph-check |
| Warning | Warning | WarningIcon | ph-warning |
| Error | XCircle | XCircleIcon | ph-x-circle |
| Info | Info | InfoIcon | ph-info |
| Eye/Show | Eye | EyeIcon | ph-eye |
| Hide | EyeSlash | EyeSlashIcon | ph-eye-slash |
| Filter | Funnel | FunnelIcon | ph-funnel |
| Sort | SortAscending | SortAscendingIcon | ph-sort-ascending |
| Calendar | Calendar | CalendarIcon | ph-calendar |
| Clock/Time | Clock | ClockIcon | ph-clock |
| Envelope | EnvelopeIcon | ph-envelope | |
| Phone | Phone | PhoneIcon | ph-phone |
| Chat | ChatCircle | ChatCircleIcon | ph-chat-circle |
| Lock/Auth | Lock | LockIcon | ph-lock |
| Logout | SignOut | SignOutIcon | ph-sign-out |
For brand logos (GitHub, Stripe, Vercel, etc.), use svgl.app instead — see the svgl skill.
Phosphor is for UI icons, svgl is for brand logos.
| Context | Size | Why |
|---|---|---|
| Inline with body text | 16px | Matches text baseline |
| Buttons | 16-20px | Proportional to button text |
| Navigation items | 20-24px | Visible at sidebar scale |
| Card headers | 24-32px | Visual anchor for content |
| Feature/hero sections | 32-48px | Decorative emphasis |
| Empty states | 48-64px | Large illustration role |
Duotone renders a two-tone version with one layer at 20% opacity. It's the most visually rich weight — use it for feature showcases, onboarding, and marketing sections.
In React, the secondary layer inherits the icon's color at reduced opacity. You can target
layers via CSS if needed:
/* Target the background layer of duotone icons */
.ph-duotone::before { opacity: 0.15; }
One weight per region. Don't mix regular and bold in the same nav. Use fill for active states alongside regular for inactive — that's the only acceptable mix.
Prefer currentColor. Don't set explicit colors unless the icon needs to differ from
surrounding text. Icons that inherit color stay consistent with theme changes.
Always add alt or aria-label for icons that convey meaning without adjacent text.
Decorative icons next to labels can use aria-hidden="true".
Use optimizePackageImports in Next.js. Without it, dev startup is painfully slow.
SSR = /ssr import. Server Components cannot use IconContext.
Brand logos go through svgl.app, not Phosphor. Phosphor is for UI iconography.