@sumcode/svgify
Version:
A lightweight React component designed to dynamically render and style SVG icons.
371 lines (282 loc) โข 12.5 kB
Markdown
# ๐จ Svgify
<div style="display:flex; justify-content:center; margin-inline: auto; margin-block: 3rem 1rem; width: 100%;">
<img src="https://res.cloudinary.com/dclbtusww/image/upload/v1725670993/Sumcode/Svgify/spkctkwkydsmnvki85di.png" alt="Svgify Logo" style="width: 100%; object-fit: contain;" />
</div>
<br/>
`Svgify` is a lightweight React component designed to dynamically render and style SVG icons with smart color mixing and transparency preservation. It fetches SVG files and automatically adapts them to use `currentColor`, making them fully themeable.
## โจ Key Updates (v4.0.0 - Beta)
### ๐จ Smart Color Mixing
- **Automatic transparency preservation** using CSS `color-mix()` function
- **Opacity detection** from both `opacity` attributes and color alpha channels
- **Duotone icon support** - preserves multi-color icons with varying transparency levels
### ๐ฏ Enhanced FontWeight Modes
- **`default`**: Preserves original icon structure (fill-only, stroke-only, or both)
- **`fill`**: Forces all elements to use fill only
- **`stroke`**: Forces all elements to use stroke only
- **`both`**: Forces all elements to have both fill and stroke
### โ๏ธ React 19 Compatible
- Fully tested and compatible with React 19.x
- Uses latest React patterns and hooks
### โก Next.js Compatible
> **โ
NEW:** Full Next.js support (App Router & Pages Router)
Svgify now works seamlessly with Next.js! The library includes proper `"use client"` directives and is fully compatible with both the App Router and Pages Router.
**Quick Start for Next.js:**
1. Wrap your app with the `Svgifier` provider (in a client component)
2. Use the `Svgify` component in any client component
```jsx
// app/providers.tsx (App Router)
"use client";
import { Svgifier } from "@sumcode/svgify";
export function Providers({ children }) {
return <Svgifier base_path="/assets/icons">{children}</Svgifier>;
}
```
```jsx
// components/MyIcon.tsx
"use client";
import Svgify from "@sumcode/svgify";
export function MyIcon() {
return <Svgify IconName="home" Scale={1.5} />;
}
```
๐ **[See full Next.js documentation](#-nextjs-usage)** below for complete setup instructions.
## ๐ Features
- ๐ฏ **Dynamic SVG Rendering:** Fetches and displays SVG icons based on the provided `IconName`
- ๐จ **Smart Color Mixing:** Automatically converts colors to use `currentColor` while preserving transparency
- ๐ **Duotone Support:** Handles icons with multiple colors and transparency levels
- ๐
**Customizable Styling:** Supports inline styles, CSS classes, and different font weights
- ๐ **Scalable Icons:** Adjust the size of your icons with the `Scale` factor
- โก **Icons Caching:** Icons are cached in `localStorage` for better performance
- ๐ญ **Class-based SVG Support:** Automatically inlines `<style>` blocks and removes classes
##








> **โ ๏ธ Note:** The new color mixing and duotone features are in beta. Please report any issues you encounter.
## ๐ฆ Installation
Install the package via npm:
```bash
npm install @sumcode/svgify
```
~~Add StyleSheet to your _`App.jsx`_ file:~~ (No longer needed in v4.0.0+)
```js
// import "@sumcode/svgify/styles"; // Not needed anymore
```
### ๐ Folder Structure
- Create folder _`public/assets/icons`_
- Add your _`YOUR_ICON_NAME.svg`_ files
```
.
โโโ my-project
โโโ node_modules
โโโ public
โ โโโ assets
โ โโโ icons ๐ (Add your svg icons here)
โ โโโ YOUR_ICON_NAME.svg
โโโ src
โโโ app.jsx
```
## ๐ฏ Basic Usage
```jsx
import Svgify from "@sumcode/svgify";
function App() {
return (
<div style={{ color: "blue" }}>
{/* Icon will inherit blue color */}
<Svgify IconName="YOUR_ICON_NAME" Scale={1.2} />
</div>
);
}
```
## ๐จ FontWeight Modes
```jsx
import Svgify from "@sumcode/svgify";
function App() {
return (
<div>
{/* Default: preserves original structure */}
<Svgify IconName="icon" FontWeight="default" />
{/* Fill only: forces fill on all elements */}
<Svgify IconName="icon" FontWeight="fill" />
{/* Stroke only: forces stroke on all elements */}
<Svgify IconName="icon" FontWeight="stroke" />
{/* Both: forces both fill and stroke */}
<Svgify IconName="icon" FontWeight="both" />
</div>
);
}
```
## ๐จ Duotone Icons (Beta)
Svgify automatically handles duotone icons by preserving transparency:
```jsx
// Icon with opacity="0.5" will be rendered as:
// fill="color-mix(in srgb, currentColor 50%, transparent)"
<Svgify IconName="duotone-icon" />
```
## ๐ Version Control (Recommended)
```jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import { Svgifier } from "@sumcode/svgify/SvgifyContext";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<Svgifier version={1} clearForOldVersion>
<App />
</Svgifier>
</StrictMode>
);
```
| Parameter | Type | Default | Description |
| :------------------- | :-------- | :--------------- | :------------------------------------------------------------------------------ |
| `version` | `number` | `1` | Current icon version (increment to clear cache) |
| `clearForOldVersion` | `boolean` | `false` | Enable for upgrading from versions < 2.0.0 |
| `base_path` | `string` | `/assets/icons/` | Path to icons folder from public directory |
| `FetchIcon` | `function`| `axios.get` | Custom fetch function (see section below) |
## ๐ง Custom Fetching Function
```jsx
import { Svgifier } from "@sumcode/svgify/SvgifyContext";
import axios from "axios";
const FetchIcon = async (icon_path: string) => {
return axios.get(`http://YOUR_SERVER.com/${icon_path}`);
};
createRoot(document.getElementById("root")!).render(
<StrictMode>
<Svgifier
base_path="/assets/iconization"
version={2}
FetchIcon={FetchIcon}
clearForOldVersion
>
<App />
</Svgifier>
</StrictMode>
);
```
## ๐ Next.js Usage
Svgify is fully compatible with Next.js 13+ (App Router) and Next.js 12 (Pages Router). Since the library uses browser APIs like `localStorage` and `DOMParser`, components must be marked as client components.
### App Router (Next.js 13+)
**Step 1:** Create a providers component
```jsx
// app/providers.tsx
"use client";
import { Svgifier } from "@sumcode/svgify";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<Svgifier
base_path="/assets/icons"
version={1}
clearForOldVersion={true}
>
{children}
</Svgifier>
);
}
```
**Step 2:** Use in your root layout
```jsx
// app/layout.tsx
import { Providers } from "./providers";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
```
**Step 3:** Use Svgify in client components
```jsx
// components/MyComponent.tsx
"use client";
import Svgify from "@sumcode/svgify";
export function MyComponent() {
return (
<div>
<Svgify IconName="home" Scale={1.5} />
<Svgify IconName="user" className="text-blue-500" />
</div>
);
}
```
### Pages Router (Next.js 12)
**Step 1:** Wrap your app in `_app.tsx`
```jsx
// pages/_app.tsx
import { Svgifier } from "@sumcode/svgify";
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
return (
<Svgifier base_path="/assets/icons" version={1}>
<Component {...pageProps} />
</Svgifier>
);
}
```
**Step 2:** Use Svgify in your pages or components
All components using Svgify must include the `"use client"` directive:
```jsx
// components/IconComponent.tsx
"use client";
import Svgify from "@sumcode/svgify";
export default function IconComponent() {
return <Svgify IconName="settings" FontWeight="fill" />;
}
```
### Important Next.js Notes
- โ
Always use `"use client"` directive in components that use Svgify
- โ
Place SVG files in the `public/assets/icons/` directory
- โ
Icons are cached in `localStorage` for better performance
- โ ๏ธ Server components cannot use Svgify (browser APIs required)
## โ๏ธ Component Props
| Parameter | Type | Default | Description |
| :---------------- | :----------------------- | :---------- | :--------------------------------------------------------------- |
| `IconName` | `string`* | `""` | Icon name without extension |
| `FontWeight` | `string` | `"default"` | Display mode: `"default"` \| `"fill"` \| `"stroke"` \| `"both"` |
| `Scale` | `number` | `1` | Size multiplier (applied to font-size) |
| `className` | `string` | `""` | Custom CSS class for the wrapper span |
| `style` | `React.CSSProperties` | `{}` | Inline styles for the wrapper span |
| `LoadingElement` | `"" \| React.ReactNode` | `""` | Element shown while loading |
| `NotFoundElement` | `"" \| React.ReactNode` | `""` | Element shown on error |
## ๐ How It Works
### Color Processing Pipeline
1. ๐ **Style Inlining**: Converts `<style>` blocks to inline styles
2. ๐๏ธ **Opacity Detection**: Reads `opacity` attributes and color alpha channels
3. ๐จ **Color Mixing**: Replaces colors with `color-mix(in srgb, currentColor X%, transparent)`
4. โ๏ธ **FontWeight Application**: Applies fill/stroke logic based on mode
### Example Transformation
```xml
<!-- Input SVG -->
<path opacity="0.5" fill="#FF0000" />
<!-- Output (processed by Svgify) -->
<path fill="color-mix(in srgb, currentColor 50%, transparent)" stroke="none" />
```
## ๐งช Testing
Exhaustive testing with 10K randomly generated icons: [๐ Live Demo](https://svgify-exhaustive.netlify.app/)
## ๐ Changelog
### v4.0.0 (Beta)
- โจ Smart color mixing with transparency preservation
- โจ Duotone icon support
- โจ Enhanced FontWeight modes (default, fill, stroke, both)
- โ๏ธ React 19 compatibility
- โก Next.js compatibility (App Router & Pages Router)
- ๐ Removed CSS dependency
- ๐ Fixed icon update on prop change
## ๐จโ๐ป Author
**Mohammed Atef**
- ๐ผ [LinkedIn](https://www.linkedin.com/in/m7mmed3atef/)
- ๐ [Github](https://github.com/M7mmedATeF)
- ๐ง [Email](mailto:mohammed.atef.ewais@gmail.com)
## ๐ License
MIT ยฉ [Mohammed Atef](https://github.com/M7mmedATeF)