Skip to content
Back to skills

Icon System Stinger

ASecurity

Design a React icon system. Use for library choice, bundle size, SVG sprites, dynamic icons, or accessibility. Read README.md for the guide map.

  • 85 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 9, 2026
developmenttypescriptgoreactnextjsgitdevops

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned September 27, 2026

npx -y skills add legioncodeinc/vibe-coding-tools --skill icon-system-stinger --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Icon System Stinger?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Icon System Stinger
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/legioncodeinc-icon-system-stinger/badge)](https://www.skillsdirectory.com/skills/legioncodeinc-icon-system-stinger)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: "icon-system-stinger"
license: AGPL-3.0-or-later
description: "Design a React icon system. Use for library choice, bundle size, SVG sprites, dynamic icons, or accessibility. Read README.md for the guide map."
---

# icon-system Stinger

Procedural arsenal for `icon-system-wasp-drone`. Encodes the canonical icon library selection matrix, the tree-shake-vs-SVG-sprite delivery decision, the dynamic-import-by-name pattern, custom SVG component conventions, and the accessibility contract covering the three icon categories (decorative, semantic, interactive).

---

## When this stinger applies

Load when `icon-system-wasp-drone` is invoked. Typical triggers:

- "Which icon library should we use?"
- "My icon imports are bloating the bundle"
- "How do I load an icon by name at runtime?"
- "Build me a reusable icon component"
- "Audit our icons for accessibility"
- "Should I use an SVG sprite?"
- "Icon button has no accessible name"

Do NOT load for:

- Icon size and color tokens (ux-ui-svelte-wasp-drone owns those)
- General React component architecture (react-wasp-drone)
- SVG sprite build-pipeline tooling at the bundler level (devops-wasp-drone)
- General bundle-optimization strategies beyond icon imports (devops-wasp-drone)

---

## First action when this stinger is loaded

1. Read `guides/00-library-selection-matrix.md`: pick the right icon library first.
2. Read `guides/01-tree-shake-vs-sprite.md`: choose the delivery strategy.
3. Read the per-task guide relevant to the request (02 through 04).
4. Use `templates/icon-audit-report.md` to structure any output audit report.

---

## Library selection matrix (summary)

| Library | Best for | Icon count | Tree-shaking |
|---|---|---|---|
| **Lucide** | Default React/Next.js apps; best DX | 1400+ | Named ESM exports; full |
| **Heroicons** | Tailwind CSS projects; curated small set | ~292 | Named ESM by variant path |
| **Tabler** | Admin UIs needing extensive coverage | 5500+ | Named ESM per icon |
| **Phosphor** | Design systems needing weight variants | 1300+ | Named ESM; weight is a prop |
| **Iconify** | Multi-library mixing OR large on-demand sets | 200,000+ | Static bundled or CDN |

See `guides/00-library-selection-matrix.md` for the full decision table with edge cases and installation snippets.

---

## Tree-shake vs SVG sprite (summary)

| Strategy | When to choose |
|---|---|
| Named ESM imports (default) | Single app, defined icon set, <200 icons |
| SVG sprite | Icons needed in 3+ separate JS bundles; non-React rendering contexts |
| Iconify on-demand (CDN) | Large icon sets where most icons appear on few pages; admin tools only |

See `guides/01-tree-shake-vs-sprite.md` for the full decision matrix and Vite/Next.js configuration snippets.

---

## Dynamic icon by name (summary)

For cases where the icon name arrives as a string prop at runtime:

```tsx
// Safe approach: static map built at compile time
import * as LucideIcons from 'lucide-react';
import type { LucideIcon } from 'lucide-react';

const iconMap: Record<string, LucideIcon> = LucideIcons as any;

function DynamicIcon({ name, ...props }: { name: string } & LucideProps) {
  const Icon = iconMap[name];
  if (!Icon) return null;
  return <Icon {...props} />;
}
```

Do NOT use `React.lazy` per-icon for above-the-fold content. See `guides/02-dynamic-import-icon-name.md` for the full pattern, TypeScript safety, and RSC boundary guidance.

---

## Accessibility contract (summary)

| Icon category | Required attributes |
|---|---|
| Decorative (has adjacent text) | `aria-hidden="true"` + `focusable="false"` on SVG |
| Semantic (standalone, no text) | `aria-label` on container OR `role="img"` + `<title>` on SVG |
| Interactive (icon button) | `aria-label` on `<button>`; SVG gets `aria-hidden="true"` |

See `guides/03-accessibility-contract.md` for implementation details and axe-core failure modes. Source: `research/external/icon-accessibility.md`.

---

## Critical directives

- **Never import from a library's barrel root unless tree-shaking is guaranteed.** Barrel imports from `some-icon-lib` without ESM named exports bundle every icon. Use named imports or path imports. See `guides/01-tree-shake-vs-sprite.md`.
- **Always apply the decorative-vs-semantic distinction.** Every icon must either be hidden from AT (`aria-hidden="true"`) or carry an accessible name. Unlabeled icon buttons are a WCAG 2.1 Level A failure.
- **Never use dynamic-by-name for SSR-critical above-the-fold icons.** Dynamic imports introduce loading waterfalls; use static named imports for hero content.
- **Prefer Iconify only when multi-library mixing is genuinely needed.** Single-library projects pay Iconify's runtime overhead without benefit.
- **Custom SVG components must set `focusable="false"` on the `<svg>` element.** Without it, SVGs receive keyboard focus in legacy Edge and some screen readers.

---

## Folder layout

```
icon-system-stinger/
├── SKILL.md                              (this file)
├── README.md
├── guides/
│   ├── 00-library-selection-matrix.md
│   ├── 01-tree-shake-vs-sprite.md
│   ├── 02-dynamic-import-icon-name.md
│   ├── 03-accessibility-contract.md
│   └── 04-custom-svg-component.md
├── examples/
│   ├── lucide-icon-component.md
│   └── dynamic-icon-loader.md
├── templates/
│   └── icon-audit-report.md
├── reports/
│   └── README.md
└── research/
    ├── research-plan.md
    ├── research-summary.md
    ├── index.md
    ├── internal/
    │   └── command-brief.md
    └── external/
        ├── lucide-react.md
        ├── iconify-react.md
        ├── heroicons-tabler-phosphor.md
        ├── icon-sprite-patterns.md
        └── icon-accessibility.md
```

---

*Forged by stinger-forge from `icon-system-wasp-drone-command-brief.md` and `research/`. Part of The Wasp Nest by [Mario Aldayuz a.k.a @thenotoriousllama](https://github.com/thenotoriousllama).*

Files in this skill

  • README.md681 B
  • SKILL.md6.3 KB
  • examples/dynamic-icon-loader.md3.4 KB
  • examples/lucide-icon-component.md2.7 KB
  • guides/00-library-selection-matrix.md2.9 KB
  • guides/01-tree-shake-vs-sprite.md3.2 KB
  • guides/02-dynamic-import-icon-name.md3.7 KB
  • guides/03-accessibility-contract.md4.1 KB
  • guides/04-custom-svg-component.md3.9 KB
  • reports/README.md386 B
  • research/external/heroicons-tabler-phosphor.md2.6 KB
  • research/external/icon-accessibility.md2.9 KB
  • research/external/icon-sprite-patterns.md2.3 KB
  • research/external/iconify-react.md1.9 KB
  • research/external/lucide-react.md1.7 KB
  • research/index.md920 B
  • research/internal/command-brief.md1.7 KB
  • research/research-plan.md1.4 KB
  • research/research-summary.md3.7 KB
  • templates/icon-audit-report.md2.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…