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

@whydrf/nava-icon-web-components

v1.5.0

Published

Web Components for Nava Icons

Readme


What is this?

@whydrf/nava-icon-web-components is the framework-agnostic binding for Nava Icons — a collection of 950+ handcrafted SVG icons. Each icon is a native Web Component using the Custom Elements API, so it works everywhere: vanilla HTML, React, Vue, Angular, Svelte, Solid, Lit — any framework that can render HTML.

Unlike icon fonts or SVG sprites, every icon here is a proper Custom Element with Shadow DOM encapsulation. You use it in your markup exactly like any native HTML element — no framework, no build step, no configuration.

Installation

npm install @whydrf/nava-icon-web-components

Requirements: A browser that supports Custom Elements v1 (all modern browsers). No framework dependency.

Getting Started

After installation, import the package to register all icon custom elements:

<script type="module">
  import '@whydrf/nava-icon-web-components'
</script>

Once imported, every icon becomes available as a custom element. Icons follow the pattern <nava-icon-{name}> in kebab-case:

<nav>
  <nava-icon-home size="24"></nava-icon-home>
  <nava-icon-search size="24" color="gray"></nava-icon-search>
  <nava-icon-settings size="24"></nava-icon-settings>
</nav>

That's it — no framework, no components to import, no configuration. Just HTML.

Global Configuration

You can set default icon properties globally using setNavaIconConfig. All icons will use these defaults unless overridden by individual attributes.

<script type="module">
  import '@whydrf/nava-icon-web-components'
  import { setNavaIconConfig } from '@whydrf/nava-icon-web-components'

  // Set global defaults
  setNavaIconConfig({ size: 20, color: 'gray', strokeWidth: 1.5 })
</script>

<!-- All icons inherit global defaults -->
<nava-icon-home></nava-icon-home>              <!-- size=20, color="gray" -->
<nava-icon-search size="24"></nava-icon-search> <!-- size=24 overrides — rest inherited -->

Attributes always override global configuration. If you pass size="32" on an element, that takes priority over the global size.

You can read the current configuration at any time:

import { getNavaIconConfig } from '@whydrf/nava-icon-web-components'
console.log(getNavaIconConfig()) // { size: 20, color: 'gray', strokeWidth: 1.5 }

How Tree Shaking Works

When you import the package in a <script type="module">, only the icons actually used in your HTML are included in the final bundle. The build tool (Vite, Rollup, webpack, esbuild) traces which custom elements are referenced and eliminates the rest.

Important: Tree shaking only works with static imports in a module context. If you dynamically add icon elements at runtime (via document.createElement), all icons will be included because the bundler can't trace them.

<!-- ✅ Tree-shakeable — only home and search are bundled -->
<script type="module">
  import '@whydrf/nava-icon-web-components'
</script>
<nava-icon-home size="24"></nava-icon-home>
<nava-icon-search size="24"></nava-icon-search>

Two Variants: Regular and Filled

Every icon ships in two visual styles:

  • Regular — Stroke-based outlines. Clean, minimal, and ideal for most UI contexts like navigation, toolbars, and forms.
  • Filled — Solid shapes with filled regions. Great for emphasis, active states, or when you want an icon to stand out.

You control which variant to show with the mode attribute:

<!-- Outline variant (default) -->
<nava-icon-heart size="24" mode="regular" color="gray"></nava-icon-heart>

<!-- Filled variant -->
<nava-icon-heart size="24" mode="filled" color="red"></nava-icon-heart>

<!-- Toggle with JavaScript -->
<script type="module">
  import '@whydrf/nava-icon-web-components'

  const heart = document.querySelector('nava-icon-heart')
  heart.mode = heart.mode === 'filled' ? 'regular' : 'filled'
</script>

The mode switching is instant — no re-fetching, no lazy loading. Both variants are bundled together.

Customizing Appearance

Since icons are standard SVG elements inside a Shadow DOM, you can customize them through their attributes. All attributes are reactive — changing them updates the icon instantly.

<nava-icon-home
  size="32"
  color="#6366f1"
  stroke-width="1"
  style="transition: transform 0.2s; cursor: pointer"
  onclick="handleClick()"
></nava-icon-home>

Colors

You can pass colors in any format the browser understands — hex codes, RGB, HSL, named colors, or CSS variables:

<nava-icon-home color="#1a1a2e"></nava-icon-home>              <!-- Hex -->
<nava-icon-home color="rgb(99, 102, 241)"></nava-icon-home>    <!-- RGB -->
<nava-icon-home color="oklch(65% 0.27 264)"></nava-icon-home>  <!-- OKLCH -->
<nava-icon-home color="var(--primary)"></nava-icon-home>        <!-- CSS variable -->

With Tailwind CSS, the color attribute defaults to currentColor, so Tailwind's text-* utilities work directly:

<!-- Combine color, size, and hover effects -->
<nava-icon-home class="text-emerald-400 w-8 h-8 hover:text-emerald-300 transition-colors"></nava-icon-home>

<!-- Dark mode support -->
<nava-icon-home class="text-gray-900 dark:text-white"></nava-icon-home>

CSS Custom Properties

You can theme icons using CSS custom properties that inherit through the Shadow DOM:

:root {
  --icon-color: currentColor;
  --icon-size: 24px;
}

.icon-large {
  --icon-size: 48px;
  --icon-color: #6366f1;
}
<div class="icon-large">
  <nava-icon-home size="var(--icon-size)" color="var(--icon-color)"></nava-icon-home>
</div>

Popular Icons

| Category | Icons | |----------|-------| | Arrows | arrow-back, arrow-right, arrow-from-left, arrow-to-top, refresh, redo, undo | | Interface | home, search, settings, menu, check-circle, x-circle, copy, trash | | Communication | bell, mail, phone, message-square, send, at | | Files | file, folder, download, upload, archive, clipboard | | Media | camera, image, music, video, play, pause | | Objects | star, bookmark, lock, key, award, gift | | Weather | sun, moon, cloud, droplet, wind, umbrella | | Shopping | cart, credit-card, bag, tag, badge, diamond |

Browse all 950+ icons with live preview at nava-icons.dev.

Accessibility

Icons include built-in accessibility features:

  • When you provide a title attribute, an invisible <title> element is added inside the SVG, which screen readers announce.
  • Decorative icons (no title) are implicitly aria-hidden since SVGs without titles are ignored by assistive technology.
<!-- Meaningful icon — screen reader announces "Go to homepage" -->
<nava-icon-home title="Go to homepage"></nava-icon-home>

<!-- Decorative icon — screen reader ignores it -->
<nava-icon-home></nava-icon-home>

Framework Interop

Because Web Components are a browser standard, they work everywhere. Here's how to use them in popular frameworks:

React

// React needs a small wrapper — use the npm package directly for best DX
import { HomeIcon } from '@whydrf/nava-icon-react'

Vue

<template>
  <!-- Vue supports custom elements natively -->
  <nava-icon-home :size="24" />
</template>

Angular

<!-- Angular supports custom elements natively -->
<nav>
  <nava-icon-home [attr.size]="24"></nava-icon-home>
</nav>

Svelte

<script>
  import '@whydrf/nava-icon-web-components'
</script>

<nava-icon-home size="24"></nava-icon-home>

Lit

import '@whydrf/nava-icon-web-components'
import { html, LitElement } from 'lit'

class MyApp extends LitElement {
  render() {
    return html`<nava-icon-home size="24"></nava-icon-home>`
  }
}

Plain HTML

<script type="module">
  import '@whydrf/nava-icon-web-components'
</script>

<nava-icon-home size="24"></nava-icon-home>

Dynamic Icons with JavaScript

You can create, update, and remove icons dynamically using the standard DOM API:

<script type="module">
  import '@whydrf/nava-icon-web-components'

  // Create a new icon
  const icon = document.createElement('nava-icon-home')
  icon.setAttribute('size', '24')
  icon.setAttribute('color', 'blue')
  document.body.appendChild(icon)

  // Update an existing icon
  const existing = document.querySelector('nava-icon-home')
  existing.setAttribute('mode', 'filled')
  existing.setAttribute('color', 'red')

  // Remove an icon
  existing.remove()
</script>

Note: Dynamically created icons won't benefit from tree shaking — all 950+ icons will be in your bundle.

Server-Side Rendering

Web Components don't work during SSR (the Custom Elements API is only available in the browser). For SSR frameworks, use the framework-specific Nava Icons package instead:

| Framework | Package | |-----------|---------| | React / Next.js | @whydrf/nava-icon-react | | Vue / Nuxt | @whydrf/nava-icon-vue | | Angular | @whydrf/nava-icon-angular |

If you're using a framework with partial hydration (like Astro), use the Web Components package in client islands and the framework-specific package for server-rendered content.

Attributes Reference

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | size | number \| string | 24 | Width and height in pixels | | color | string | currentColor | SVG stroke/fill color. currentColor inherits from parent CSS | | stroke-width | number \| string | 0.5 | Controls line thickness for stroke-based icons | | mode | "regular" \| "filled" | "regular" | Toggles between outline and solid variants | | title | string | — | Accessible title for screen readers |

All standard HTML attributes (class, style, onclick, onmouseenter, data-*, aria-*, etc.) are also supported.

Custom Element Naming

Each icon is registered as a custom element with the prefix nava-icon- followed by the kebab-case icon name. Examples:

| Import Name | Custom Element | |-------------|----------------| | HomeIconComponent | <nava-icon-home> | | CheckCircleIconComponent | <nava-icon-check-circle> | | ArrowRightIconComponent | <nava-icon-arrow-right> | | CommandLineIconComponent | <nava-icon-command-line> |

License

MIT © whydrf