npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@orvain/icons

v0.1.3

Published

Orvain Design System — shared SVG icons (one module per icon) consumed by Vue and React

Readme

@orvain/icons

The shared SVG icons behind the Orvain Design System — outline icons (one style, stroked in currentColor), consumed by both @orvain/react and @orvain/vue. Every icon is its own module, so a bundler ships only the icons you import.

Icons are one-colour glyphs that follow currentColor. Multi-colour artwork (brand logos, country flags, emoji, file-type badges and the empty-state illustrations) lives in @orvain/assets.

Commercial software. See LICENSE — use is governed by your agreement with Orvain Labs.

Install

npm install @orvain/icons

Most people never install this directly — it ships as a dependency of @orvain/react and @orvain/vue, and you render icons through their <Icon> component:

import { Icon } from '@orvain/react';
import { iconClockAdd, iconTrash } from '@orvain/icons';

<Icon icon={iconClockAdd} size={20} />
<Icon icon={iconTrash} title="Delete" />   {/* labelled, exposed to assistive tech */}
<Icon name="clock-add" />                  {/* by name: draws the icon registered as "clock-add" */}

Names need the icon to be registered once at start-up (see Icons by name).

Install it on its own when you need the raw path data — for a canvas renderer, a PDF exporter, or an icon picker UI.

Usage

import { iconClockAdd } from '@orvain/icons';
// { name: 'clock-add', viewBox: '0 0 24 24', body: '<path …/>' }

import { iconRegistry, iconNames, type IconName } from '@orvain/icons';
const def = iconRegistry['clock-add']; // the same object as iconClockAdd

| Export | What it is | |---|---| | iconChevronDown, iconClockAdd, … | one IconDefinition per icon: icon + the name in PascalCase (arrow-up-01 → iconArrowUp01). Only the ones you import are bundled. | | registerIcons(…) | makes icons renderable by name (see below) | | lookupIcon(name) | the registered icon for a name, or undefined | | iconRegistry | Record<IconName, IconDefinition>: every icon, keyed by name. Using it includes every icon. | | iconNames | the list of built-in names (includes every icon) | | IconName | a string-literal union of those names, so typos fail to compile | | IconSource | IconName \| IconDefinition: what the components' icon props accept (needs TypeScript ≥ 5.4) | | isIconDefinition, iconNameOf | tell a definition from other values; get an icon's name from a name or definition | | defaultIconViewBox, defaultIconStrokeWidth | rendering defaults | | getIconsVersion, subscribeIcons | low level, for renderers: re-render when icons are registered |

body is a raw SVG fragment intended to be injected inside an <svg> element with the matching viewBox. It uses currentColor, so icons inherit the colour of their container.

Icons by name

<Icon name="…"> and every component prop that takes an icon name draw the icon registered under that name. Nothing is registered by default. The icons the components draw on their own (chevrons, close, check marks, spinners, status icons, defaults) are imported as definitions inside each component, so they always render and need no registration; only names an app passes in do. Register once, in the app's entry file, before the first render:

import { registerIcons, iconBellRing, iconCheckCircle } from '@orvain/icons';
registerIcons(iconBellRing, iconCheckCircle);   // also takes arrays and objects: registerIcons({ iconBellRing }, [iconCheckCircle])

import '@orvain/icons/all';                     // or: every icon (~100 KB gzipped)

| Setup | In the bundle | Names render | |---|---|---| | definitions only (icon={iconBellRing}) | those icons | no names needed | | registerIcons(…) with the icons used by name | those icons (about 0.2 KB gz each) | synchronously, server-side too | | import '@orvain/icons/all' | every icon, ~100 KB gz | synchronously, server-side too | | import('@orvain/icons/all') (lazy) | a ~100 KB gz chunk, loaded after start-up | once the chunk lands; not in server HTML | | nothing | no icons | not at all: an empty <svg> and a development warning per name |

Custom icons. A definition is plain data: { name: 'acme-logo', viewBox: '0 0 24 24', body: '<path d="…" stroke="currentColor"/>' }. Pass it directly (<Icon icon={acmeLogo} />, icon={acmeLogo} on any icon prop), which needs no registration. For names that arrive as data (a CMS, a config file), registerIcons(acmeLogo) makes 'acme-logo' resolvable like a built-in name; registering a built-in name replaces that icon. IconName lists only the built-in names, so a custom name from typed code needs a cast; prefer the definition there.

Why registration and not automatic lookup. A component only sees a name string at runtime, so no bundler can tell which icons a name will need: either every icon ships with any component that accepts a name (the old default, ~100 KB gz for a Tooltip), or names are resolved asynchronously (a flash, and missing from server-rendered HTML), or the app says which names it uses. This package does the last: explicit, synchronous and SSR-safe, and it needs no bundler configuration. The library never loads icons on its own: a dynamic import() of the full set inside the package would land in the initial bundle under esbuild (inlined without code splitting, pulled into a shared chunk with it). An SVG sprite was not used either: it needs the app to serve an asset file, and the shadow tree of <use> would stop components from styling individual icon paths.

@orvain/icons/all

A side-effect import that registers every icon (listed in sideEffects). Storybook and the landing page use it.

@orvain/icons/resolve

resolveIcon(nameOrDefinition) returns the definition: definitions pass through, names resolve when registered. withIconNames(component) returns the component; the component packages export their name-taking components through it.

Accessibility

Icon bodies carry no <title> and no roles — labelling belongs to whatever renders them. The <Icon> components in @orvain/react and @orvain/vue mark icons aria-hidden="true" unless given title, aria-label or aria-labelledby. Do the same if you render the definitions yourself.

Adding icons (maintainers)

Icons are authored in src/registry.ts, the single source of truth. scripts/gen-icons.mjs (run by pnpm build, or pnpm gen:icons) generates the per-icon modules, the barrel and the registry built from them into src/generated/ (gitignored). It fails when two names map to the same export name.

Known limitations

  • iconRegistry, iconNames and @orvain/icons/all include every icon (~410 KB raw, ~100 KB gzipped). Import definitions, or register only the icons used by name, to avoid that.
  • IconSizeToken and iconSizeMap are deprecated and will be removed in the next major.

Related packages