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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.