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 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-svg-image

v1.0.1

Published

React-compatible conversion of SVG to images

Downloads

5

Readme

React SVG Image

Convert an SVG JSX element into an image (either a data URI, or a Blob, as PNG, JPEG or WEBP). This can be very useful if rendering something other than HTML in browser environments, such as PDFs.

Built in typescript definitions, published as module, around 1.4Kb minified and gzipped, no dependencies (although you will need React in your project).

This library is based on https://github.com/JuanIrache/d3-svg-to-png.

Installation

npm install react-svg-image

Setup

You must provide a "render" function - this is similar to whatever you are doing to render your React app (i.e. ReactDOM.render for 16 & 17, or ReactDOM.createRoot and root.render() for 18) - but it must return a Promise that resolves when the render has completed.

Sample renderAsPromise for React 16 and 17

import ReactDOM from "react-dom";
import { setDomRenderer } from "react-svg-image";

// For React 16.x and 17.x
async function renderAsPromise(el, domEl) {
  return new Promise((resolve) => {
    ReactDOM.render(el, domEl, resolve);
  });
}

// This only needs to be done once in your app, before you can use the library
setDomRenderer(renderAsPromise);

Sample renderAsPromise for React 18

import ReactDOM from "react-dom";
import { setDomRenderer } from "react-svg-image";

// For React 18.x, where ReactDOM.render is deprecated.
async function renderAsPromise(el, domEl) {
  const root = ReactDOM.createRoot(domEl);
  root.render(el);
  return new Promise((resolve) => {
    requestIdleCallback(resolve);
  });
}

// This only needs to be done once in your app, before you can use the library
setDomRenderer(renderAsPromise);

Usage

Once you've added your render function as above, you are ready to use the library.

There are some very lightweight examples that you can quickly view with yarn examples from the root of the repository (note - the examples in that folder are built with "jsx-at-runtime", using htm, but the idea is the same in a "normal" react app).

Here's a more standard react app example:

import React from "react";
import ReactDOM from "react-dom";

const SvgThing = ({ color }) => {
  return (
    <svg width="100" height="100">
      <circle
        cx="50"
        cy="50"
        r="40"
        stroke="black"
        strokeWidth="3"
        fill={color}
      />
    </svg>
  );
};

const SomeComponent = () => {
  const [color, setColor] = React.useState("#ff0000");
  const [src, setSrc] = React.useState(null);

  const onClick = async () => {
    // make sure you called `setRenderer` first!
    const src = await renderSvgAsImage(<SvgThing color={color} />);
    setSrc(src);
  };

  return (
    <div>
      <input
        type="color"
        value={color}
        onChange={(e) => setColor(e.target.value)}
      />
      <button onClick={onClick}>Render</button>
      {src ? <img src={src} /> : <>No image set yet</>}
    </div>
  );
};

Working with @react-pdf/renderer

React PDF has support for SVG itself, but not the full specification, for example you can't use stroke-dashoffset.

Fortunately react-pdf has support for providing an async function as the src prop of an Image component, so we can use that to render the SVG as an image and then use that image in the PDF.

import React from "react";
import { Document, Page, View, Image } from "@react-pdf/renderer";
import { renderSvgAsImage, setDomRenderer } from "react-svg-image";

// For React 16.x and 17.x
async function renderAsPromise(el, domEl) {
  return new Promise((resolve) => {
    ReactDOM.render(el, domEl, resolve);
  });
}

setDomRenderer(renderAsPromise);

// Note the use of an SVG property, `strokeDasharray` that is not supported by
// `@react-pdf/renderer`
const SvgIcon = ({ color }) => {
  return (
    <svg width="100" height="100">
      <circle
        cx="50"
        cy="50"
        r="40"
        stroke="black"
        strokeDashoffset="100"
        strokeDasharray="100"
        strokeWidth="3"
        fill={color}
      />
    </svg>
  );
};

export const PdfDocument = () => {
  return (
    <Document>
      <Page>
        <View>
          <Image src={() => renderSvgAsImage(<SvgIcon color="#ff6600" />)} />
        </View>
      </Page>
    </Document>
  );
};

Wrapper Component for <Image>

It's fairly straighforward to make your own component to tidy up the code a bit, you could have an SvgImage.js file like this:

import React from "react";
import { Image } from "@react-pdf/renderer";
import { renderSvgAsImage } from "react-svg-image";

// Wrapper component for `<Image />`, passing on all props but handling
// children with `renderSvgAsImage`
export const SvgImage = ({ children, ...props }) => {
  return <Image {...props} src={() => renderSvgAsImage(children)} />;
};

And then use it like this:

import React from "react";
import { Document, Page, View } from "@react-pdf/renderer";

import { SvgImage } from "./SvgImage";


export const PdfDocument = () => {
  return (
    <Document>
      <Page>
        <View>
          <SvgImage><SvgIcon color="#ff6600" /></SvgImage>
        </View>
      </Page>
    </Document>
  );
};

Limitations

  • The SVG element will be rendered in a new react app, which means you won't get any Context ...

    You could pass in <ContextProvider><svg>...</svg></ContextProvider> if you wanted to, but it's obviously awkward.

  • In a similar vein, since we are rendering this "outside your app", there may other limitations on "globals".

  • Image format support is browser-dependent

  • If you're rendering to jpeg, you will probably need to specify a background color for your SVG