$npx -y skills add emilkowalski/skills --skill pick-ui-libraryPick the right library for a given frontend task from a curated, opinionated list — numbers, OTP inputs, charts, command menus, virtualization, drag and drop, toasts, state, styling, and more. Only runs when explicitly invoked; it does not trigger on its own.
| 1 | # Picking The Right Library |
| 2 | |
| 3 | A lookup skill. When invoked with a task ("I need toasts", "what should I use for drag and drop?"), match the task to the curated list below and recommend the library. These are deliberate, taste-driven picks — don't substitute alternatives outside this list unless the user asks for one or the task genuinely isn't covered. |
| 4 | |
| 5 | ## How to use this |
| 6 | |
| 7 | 1. **Identify the task**, not the library the user named. "I need to show a dropdown" is a UI-primitives task (base-ui), even if they asked about something else. |
| 8 | 2. **Check what's already installed.** Look at `package.json` first. If the project already uses a listed library, use it. If it uses a competitor (e.g. react-window instead of Virtuoso), flag the recommendation but don't churn the dependency without being asked. |
| 9 | 3. **Recommend one library**, state what it's for in one sentence, and install/wire it up if that's part of the request. Don't present a menu of options when the list has a clear answer. |
| 10 | 4. If the task isn't covered by the list, say so explicitly and recommend from your own knowledge — but be clear you've left the curated list. |
| 11 | |
| 12 | ## The list |
| 13 | |
| 14 | ### UI components & primitives |
| 15 | |
| 16 | | Task | Library | |
| 17 | | --- | --- | |
| 18 | | Unstyled, accessible UI components (dialogs, popovers, menus, selects…) | [base-ui](https://base-ui.com) | |
| 19 | | Command menus (⌘K palettes) | [cmdk](https://cmdk.paco.me) | |
| 20 | | Toasts / notifications | [Sonner](https://sonner.emilkowal.ski) | |
| 21 | | One-time password / verification code inputs | [input-otp](https://input-otp.rodz.dev) | |
| 22 | | Customizable GUIs / control panels | [Leva](https://github.com/pmndrs/leva) — [dialkit](https://joshpuckett.me/dialkit) is an alternative | |
| 23 | |
| 24 | ### Motion & visuals |
| 25 | |
| 26 | | Task | Library | |
| 27 | | --- | --- | |
| 28 | | General-purpose animation (springs, layout animations, enter/exit) | [motion](https://motion.dev) (Framer Motion) | |
| 29 | | Animating numbers (counters, prices, stats) | [NumberFlow](https://number-flow.barvian.me) | |
| 30 | | Animated text components | [torph](https://torph.lochie.me/) | |
| 31 | | 3D globes | [Cobe](https://cobe.vercel.app) | |
| 32 | | Dynamic OG images (HTML/CSS → SVG/PNG) | [Satori](https://github.com/vercel/satori) | |
| 33 | | Syntax highlighting | [shiki](https://shiki.style) | |
| 34 | |
| 35 | Reach for motion when you need springs, layout animations, exit animations, or gesture-driven values. A simple hover or fade doesn't need it — plain CSS transitions are the right tool there. |
| 36 | |
| 37 | ### Charts |
| 38 | |
| 39 | | Task | Library | |
| 40 | | --- | --- | |
| 41 | | Real-time / streaming charts | [Liveline](https://github.com/benjitaylor/liveline) | |
| 42 | | General charts (static or interactive dashboards) | [recharts](https://recharts.org) | |
| 43 | |
| 44 | The split: if data points arrive live and the chart scrolls with time, use Liveline. Everything else is recharts. |
| 45 | |
| 46 | ### Interaction & performance |
| 47 | |
| 48 | | Task | Library | |
| 49 | | --- | --- | |
| 50 | | Drag and drop | [dnd kit](https://dndkit.com) | |
| 51 | | Virtualization (long lists, large tables) | [Virtuoso](https://virtuoso.dev) | |
| 52 | |
| 53 | ### State & styling |
| 54 | |
| 55 | | Task | Library | |
| 56 | | --- | --- | |
| 57 | | State management | [zustand](https://zustand.docs.pmnd.rs) | |
| 58 | | Constructing `className` strings conditionally | [clsx](https://github.com/lukeed/clsx) | |
| 59 | | Type-safe, variant-driven styling for Tailwind | [cva](https://cva.style) | |
| 60 | | Theme switching / dark mode (no flash on load) | [next-themes](https://github.com/pacocoursey/next-themes) | |
| 61 | |
| 62 | The styling split: clsx for ad-hoc conditional classes; cva when a component has real variants (size, intent, state) that deserve a typed API. They compose — cva uses clsx-style inputs internally. |
| 63 | |
| 64 | ## Common mismatches to catch |
| 65 | |
| 66 | - **Toasts built by hand or with a modal library** → Sonner exists for exactly this. |
| 67 | - **A `<div>`-based dropdown/dialog with manual focus handling** → base-ui, which handles accessibility, focus trapping, and dismissal. |
| 68 | - **Animating a number by re-rendering text** → NumberFlow handles digit transitions properly. |
| 69 | - **Rendering a 1,000+ row list directly** → Virtuoso before reaching for pagination hacks. |
| 70 | - **A `useState`-per-component web of props for shared state** → zustand. |
| 71 | - **Template-literal className ternaries three conditions deep** → clsx (or cva if it's variant-shaped). |