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

@nativelayer.dev/svg-insert

v0.0.2

Published

Drop an SVG into your HTML like an image. Get currentColor, CSS variables, and your full cascade for free.

Readme

svg-insert

Drop an SVG into your HTML like an image. Get currentColor, CSS variables, and your full cascade for free.


Why svg-insert ?

<img src="logo.svg"> renders an SVG as a replaced element. It is isolated from the page's CSS: currentColor, CSS custom properties, and inherited styles do not reach inside it. The only way to make an SVG respond to the page's theme or accent color is to inline it.

Inlining SVGs by hand is tedious and bloats your HTML. svg-insert does it at runtime:

  • Inherits CSS. The inlined <svg> sits in the normal DOM, so currentColor, fill: inherit, and CSS variables all work.
  • Clean markup. Write <svg-insert src="/icons/logo.svg"> instead of pasting hundreds of SVG nodes by hand.
  • Attribute forwarding. Pass id, class, aria-label, viewBox, or any attribute to the inserted <svg> via svg-* prefixed attributes on the wrapper. No JavaScript needed.
  • Optional wrapper. By default the <svg-insert> element is replaced entirely. Add keep-parent to keep it as a container.
  • Dynamic. Change src at runtime and the element re-fetches and re-injects automatically.
  • No build step. Drop one <script type="module"> in your HTML and it works.

Installation

Package managers

npm install @nativelayer.dev/svg-insert
pnpm add @nativelayer.dev/svg-insert
yarn add @nativelayer.dev/svg-insert

Then import and register:

import svgInsert from '@nativelayer.dev/svg-insert'
customElements.define('svg-insert', svgInsert)

CDN

No install. Paste directly into HTML:

<script type="module">
  import svgInsert from 'https://cdn.jsdelivr.net/npm/@nativelayer.dev/svg-insert/index.js'
  customElements.define('svg-insert', svgInsert)
</script>

Usage

Default: replace the wrapper

By default, <svg-insert> is completely replaced by the fetched <svg> element. The wrapper disappears from the DOM.

<svg-insert src="/icons/logo.svg"></svg-insert>

After (in live DOM):

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <!-- SVG content -->
</svg>

Keep the wrapper with keep-parent

Add keep-parent if you need the <svg-insert> element to remain in the DOM as a container.

<svg-insert src="/icons/logo.svg" keep-parent></svg-insert>

After (in live DOM):

<svg-insert keep-parent>
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    <!-- SVG content -->
  </svg>
</svg-insert>

Forwarding attributes to the <svg> with svg-*

Any attribute on <svg-insert> that starts with svg- is automatically stripped of the prefix and applied to the inserted <svg> element.

<svg-insert
  src="/icons/arrow.svg"
  svg-id="nav-arrow"
  svg-class="icon icon--small"
  svg-aria-label="Navigate forward"
  svg-role="img"
></svg-insert>

After (in live DOM):

<svg
  xmlns="http://www.w3.org/2000/svg"
  id="nav-arrow"
  class="icon icon--small"
  aria-label="Navigate forward"
  role="img"
>
  <!-- SVG content -->
</svg>

Core API

Attributes

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | src | string | - | URL of the SVG file to fetch and inline. Changing this at runtime triggers a new fetch. | | keep-parent | boolean | false | When present, the <svg-insert> wrapper is kept in the DOM and the <svg> is appended inside it. When absent, the wrapper is replaced entirely by the <svg>. | | svg-* | string | - | Any attribute prefixed with svg- is forwarded to the inserted <svg> element with the prefix removed. |

Observed attributes

svg-insert re-fetches and re-injects when src changes. All svg-* attributes are read and applied at fetch time, not observed individually after injection.

DOM transform

| Mode | keep-parent | Result in DOM | |------|--------------|---------------| | Replace (default) | absent | <svg-insert> is gone; <svg> is in its place | | Container | present | <svg-insert> remains; <svg> is its only child |


Examples

Icon inheriting currentColor

<style>
  .icon { fill: currentColor; width: 1em; height: 1em; }
</style>

<button style="color: hsl(220 80% 55%);">
  <svg-insert src="/icons/star.svg" svg-class="icon"></svg-insert>
  Favourite
</button>

Themed SVG with CSS custom properties

<style>
  :root { --brand: hsl(260 70% 50%); }
  .brand-icon path { fill: var(--brand); }
</style>

<svg-insert src="/img/logo.svg" svg-class="brand-icon" keep-parent></svg-insert>

Because the SVG is inlined, var(--brand) resolves correctly inside it. This is impossible with <img>.

Accessible SVG icon

<svg-insert
  src="/icons/close.svg"
  svg-aria-label="Close dialog"
  svg-role="img"
  svg-focusable="false"
></svg-insert>

Runtime src swap

<!-- use keep-parent so the element stays in the DOM after first inject -->
<svg-insert id="icon" src="/icons/moon.svg" keep-parent></svg-insert>

<button id="toggle">Toggle theme</button>

<script type="module">
  const icon = document.getElementById('icon')
  const btn  = document.getElementById('toggle')
  let dark = true

  btn.addEventListener('click', () => {
    dark = !dark
    icon.setAttribute('src', dark ? '/icons/moon.svg' : '/icons/sun.svg')
  })
</script>

Using keep-parent for layout control

<style>
  .icon-wrapper {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: hsl(220 100% 95%);
  }
  .icon-wrapper svg {
    width: 24px;
    height: 24px;
    fill: hsl(220 80% 45%);
  }
</style>

<svg-insert
  src="/icons/bell.svg"
  keep-parent
  class="icon-wrapper"
></svg-insert>

Edge cases

src swap without keep-parent

Without keep-parent, <svg-insert> is removed from the DOM after the first injection. Changing src on the detached element causes this.parentNode.replaceChild(...) to throw.

<!-- ❌ element is detached after first inject — src swap throws -->
<svg-insert id="icon" src="/icons/moon.svg"></svg-insert>

<!-- ✅ keep-parent keeps the element in the DOM -->
<svg-insert id="icon" src="/icons/moon.svg" keep-parent></svg-insert>

src not set

_fetchAndInject returns immediately. No error, no placeholder — the element stays empty until src is set.

SVG file returns 404 or non-SVG response

Non-ok responses and responses with no <svg> element are caught and logged as [svg-insert] … console errors. The page continues to function; the icon is simply absent.

Cross-origin SVGs

Requires the server to send Access-Control-Allow-Origin. Without it, fetch throws a network error.

<!-- ✅ use a CDN that serves CORS headers -->
<svg-insert src="https://cdn.jsdelivr.net/npm/your-icon-set/logo.svg"></svg-insert>

Multiple elements sharing the same src

Each element fetches independently. The browser cache covers subsequent requests, but consider <use> with a hidden <symbol> for many copies of the same icon.


Anti-patterns

Swapping src on a replace-mode element

<!-- ❌ element is gone after first inject -->
<svg-insert id="icon" src="/icons/a.svg"></svg-insert>

<!-- ✅ -->
<svg-insert id="icon" src="/icons/a.svg" keep-parent></svg-insert>

Using <img src="*.svg"> when CSS theming is needed

<!-- ❌ CSS variables and currentColor cannot reach inside an <img> SVG -->
<img src="/icons/logo.svg" style="color: var(--brand);">

<!-- ✅ -->
<svg-insert src="/icons/logo.svg" svg-class="brand-icon"></svg-insert>

Forcing dimensions with svg-width/svg-height against a viewBox

<!-- ❌ may distort or clip if aspect ratios don't match -->
<svg-insert src="/icons/logo.svg" svg-width="100" svg-height="32"></svg-insert>

<!-- ✅ size via CSS to respect the natural aspect ratio -->
<svg-insert src="/icons/logo.svg" svg-class="icon" keep-parent></svg-insert>
.icon { width: 100px; height: auto; }

No accessible label on a meaningful icon

<!-- ❌ -->
<svg-insert src="/icons/delete.svg"></svg-insert>

<!-- ✅ meaningful icon -->
<svg-insert src="/icons/delete.svg" svg-aria-label="Delete item" svg-role="img"></svg-insert>

<!-- ✅ decorative icon -->
<svg-insert src="/icons/divider.svg" svg-aria-hidden="true"></svg-insert>

Pointing src at user-supplied input without validation

// ❌
const icon = new URLSearchParams(location.search).get('icon')
el.setAttribute('src', icon) // attacker-controlled path

// ✅
const ALLOWED = ['/icons/moon.svg', '/icons/sun.svg']
const safe = ALLOWED.includes(icon) ? icon : '/icons/default.svg'
el.setAttribute('src', safe)

Security

svg-insert injects raw SVG markup into the live DOM. SVG files can contain <script> tags and event handlers. Only inline SVGs you own. See the Security section of the full docs for mitigations (CSP, server-side sanitization, allowlisting).


License

MIT License. Copyright (c) 2026 ynck-chrl.

See LICENSE for the full text.