@moreyears/icons
v2.0.0
Published
Official icon library for More Years — tree-shakeable React components and Web Components for all icon weights
Readme
@moreyears/icons
Official icon library for More Years. 1,289 icons across 6 weights, available as tree-shakeable React components and as a Web Component.
Upgrading from v1? See MIGRATION.md.
Installation
npm install @moreyears/iconsReact Usage
Import icons from the weight you want. Your bundler drops everything you do not import, so a screen using 30 icons ships about 19 KB gzipped, not the whole set.
import { Mailbox, ChatRoundDots } from '@moreyears/icons/bold';
<Mailbox />
<Mailbox size={32} color="#333" />
<ChatRoundDots size={24} strokeWidth={1.5} />Deep imports work identically and are a safe fallback for bundlers that handle barrel files poorly:
import Mailbox from '@moreyears/icons/bold/mailbox';Icon names are PascalCase versions of the slug, so chat-round-dots becomes
ChatRoundDots.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| size | number \| string | 24 | Icon size in pixels |
| color | string | "currentColor" | Icon color |
| strokeWidth | number \| string | — | Stroke width (for linear/outline weights) |
| className | string | — | Additional CSS class |
Any other prop is forwarded to the wrapper element, so you can override
aria-label or attach handlers.
Weights
broken, line-duotone, linear, outline, bold, bold-duotone
Each is its own subpath: @moreyears/icons/linear, @moreyears/icons/bold, and
so on. 48 icons do not exist in every weight; importing a missing combination is
a build error rather than a silent blank.
Choosing an icon at runtime
Pass the icon itself rather than its name. This keeps dynamic selection possible while still letting unused icons fall out of the bundle.
import { Icon } from '@moreyears/icons';
import CheckCircle from '@moreyears/icons/bold/check-circle';
import DangerCircle from '@moreyears/icons/bold/danger-circle';
const TONE_ICONS = { success: CheckCircle, error: DangerCircle };
function Toast({ tone }) {
return <Icon glyph={TONE_ICONS[tone]} size={16} />;
}Raw SVG
Every icon component carries its own source:
import Mailbox from '@moreyears/icons/bold/mailbox';
Mailbox.svg; // "<svg viewBox=\"0 0 24 24\" ...>"
Mailbox.iconName; // "mailbox"
Mailbox.iconWeight; // "bold"Or import the file directly:
import mailboxUrl from '@moreyears/icons/svgs/bold/messages-conversation/mailbox.svg';Names that appear in two categories
Seventeen slugs exist in more than one category. Each has an explicit category-qualified export, and one also holds the bare name:
import { Star } from '@moreyears/icons/bold'; // like/star
import { StarAstronomy } from '@moreyears/icons/bold'; // astronomy/starmoney/bill and list/bill are spelled MoneyBill and ListBill, because
BillList is the real icon money/bill-list. 4k exports as Icon4k.
Metadata
Icon metadata lives on its own subpath and carries no artwork, so an icon browser can enumerate the catalogue cheaply.
import { getAllIcons, getIconInfo, getIconsByCategory, getCategories }
from '@moreyears/icons/manifest';
getIconInfo('mailbox');
// { name: "Mailbox", slug: "mailbox", category: "messages-conversation", weights: [...] }
getIconsByCategory('messages-conversation');
getCategories();The manifest itself is both the default export and available as raw JSON:
import manifest from '@moreyears/icons/manifest';
import manifest from '@moreyears/icons/manifest.json';CDN / Web Component
For non-React projects, use the Web Component via CDN:
<script src="https://cdn.jsdelivr.net/npm/@moreyears/icons/dist/web-component.js"></script>
<moreyears-icon name="mailbox" weight="bold" size="24" color="#333"></moreyears-icon>
<moreyears-icon name="mailbox" weight="linear" stroke-width="1.5"></moreyears-icon>| Attribute | Default | Description |
|-----------|---------|-------------|
| name | — | Icon name (slug, display name, or full id) |
| weight | "linear" | Icon weight |
| size | "24" | Size in pixels |
| color | "currentColor" | Icon color |
| stroke-width | — | Stroke width |
The web component resolves names at runtime by design, so it contains the whole library. That is appropriate for a script tag but is why the React entry points work differently.
Building from Source
npm install
npm run build
npm testThe build emits:
dist/{weight}/{icon}.{mjs,js,d.ts}— per-icon entry pointsdist/{weight}/index.{mjs,js,d.ts}— per-weight barrelsdist/index.{mjs,js}— root entry (Icon, render helpers)dist/manifest.{mjs,js,json}— metadatadist/runtime.{mjs,js}— shared render helperdist/web-component.{js,mjs}— Web Component (IIFE for CDN, plus ESM)
Tests
npm test- render-parity asserts 1,680 render cases against golden output captured from a real v1.1.0 build, so packaging changes cannot alter artwork.
- bundle-size builds fixtures with webpack and fails if tree-shaking regresses.
- exports checks every subpath resolves under ESM and CJS, and that the naming rules produce no shadowed icons.
