Skip to content

@neodx/svg

Supercharge your SVG icons ⚡️
Modern, type-safe, and lightning-fast SVG sprite management for any frontend stack.

Why @neodx/svg?

Quick Start

1. Install

bash
npm install -D @neodx/svg
bash
yarn add -D @neodx/svg
bash
pnpm add -D @neodx/svg

2. From Config to Usage (example for vite + react)

Configure your assets

ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svg from '@neodx/svg/vite';

export default defineConfig({
  plugins: [
    react(),
    svg({
      // A "root" directory will be used to search for svg files
      inputRoot: 'src/shared/ui/icon/assets',
      // Path to generated sprite/sprites folder
      output: 'public/sprites'
    })
  ]
});

Example generated sprite (public/sprites/sprite.svg)

xml
<svg width="0" height="0">
  <symbol xmlns="http://www.w3.org/2000/svg" id="arrow-drop-down" fill="currentColor" viewBox="0 0 24 24">
    <path fill="none" d="M0 0h24v24H0z"/>
    <path d="m7 10 5 5 5-5z"/>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" id="arrow-drop-up" fill="currentColor" viewBox="0 0 24 24">
    <path fill="none" d="M0 0h24v24H0z"/>
    <path d="m7 14 5-5 5 5z"/>
  </symbol>
</svg>

Minimal Icon component

TIP

Learn more about Icon component implementing

tsx
import clsx from 'clsx';

export function Icon({ name, className, ...props }) {
  return (
    <svg
      className={clsx('select-none fill-current inline-block text-inherit box-content', className)}
      focusable="false"
      aria-hidden
      {...props}
    >
      <use href={`/sprites/sprite.svg#${name}`} />
    </svg>
  );
}

Use your Icon component

tsx
import { Icon } from './icon';

export function SomeComponent() {
  return (
    <div>
      <Icon name="arrow-drop-down" className="text-2xl" />
      <Icon name="arrow-drop-up" className="text-blue-500" />
    </div>
  );
}
This simple model enables powerful and flexible usage
tsx
import { Icon } from './icon';

export function SomeComponent() {
  return (
    <div className="flex flex-col gap-4 text-base">
      <div>
        <Icon name="common/groups" className="text-xs" />
        <Icon name="common/groups" />
        <Icon name="common/groups" className="text-2xl" />
        <Icon name="common/groups" className="text-4xl" />
        <Icon name="common/groups" className="text-6xl" />
      </div>
      <div className="flex gap-4 items-center">
        <Icon name="common/copy" className="text-xl" />
        <Icon name="logos/twitter" />
        <Icon name="logos/linkedin" className="text-4xl" />
        <Icon
          name="common/edit"
          className="bg-pink-100 text-pink-700 p-2 rounded-full border border-pink-700"
        />
      </div>
      <span className="text-sm inline-flex items-center gap-2">
        <Icon name="common/filter" />
        Small description example
        <Icon name="tool/history" />
      </span>
    </div>
  );
}

Example of using icons

3. Other setups

Integrations & Recipes

Frameworks & Icon Sources:

Recipes:

Advanced: Node.js Programmatic API

Want full control? Use the Node.js programmatic API:

js
import { createSvgSpriteBuilder } from '@neodx/svg';

const builder = createSvgSpriteBuilder({
  inputRoot: 'src/shared/ui/icon/assets',
  output: 'public/sprites',
  metadata: 'src/shared/ui/icon/sprite.gen.ts',
  group: true
});

await builder.load('**/*.svg');
await builder.build();

More Resources

Enjoy!
If you have questions or want to contribute, check out our GitHub.

Released under the MIT License.