DEV Community

vavilov2212
vavilov2212

Posted on

SVGs in React (almost everything you need to know)

SVG stands for Scalable Vector Graphic. True to its name, SVGs are infinitely scalable because they use XML syntax. This means they're essentially a set of instructions for the browser (or any program that can interpret them) to render the image. Unlike raster images (like JPEGs), SVGs don't have a fixed number of pixels, so they can be scaled to any size without losing quality.

💡 In the pre-JSON era, XML (Extensible Markup Language) was the primary way to store and transmit data on the web. It provides a set of rules for encoding and reconstructing various data formats. Interestingly, both HTML and SVG use XML syntax with tags and attributes. You can even style SVG elements with CSS just like you would style regular HTML elements!

Real-world Scenario: Rendering SVGs in React

Let's explore different ways to render SVGs in your React projects.

💡 Code mentioned in this article, can be found in this repository
GitHub - vavilov2212/render-svg-example

Rendering SVGs as Image Tags

One approach is to treat SVGs as external resources. This way, you don't need any additional configuration, and you still benefit from SVG's scalability. Simply import the path to your SVG file and use it as the src attribute of an img tag (the file must be publicly accessible).

import React, { Component } from "react";
import Logo from "../public/logo.svg";

import "./styles.css";

class App extends Component {
  render() {
    return (
      <div>
        <h1> Hello, World! </h1>
        <img src="logo.svg" className="svg" alt="My SVG Image" />
      </div>
    );
  }
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Rendering SVGs as Image Tags

Important Note: In this approach, only attributes applicable to the img tag itself will have any effect. You won't be able to directly style the underlying SVG elements within the image.

Rendering SVGs "as is" in React

Imagine you want your React components to be fully built and ready to render at initial page load, without waiting for external images to download. While simply including the SVG code within your component's markup might seem like an option, it's inefficient. We want to store static resources like SVGs separately from our JavaScript code.

However, there's a catch. When you try to import an SVG file into your component, JavaScript module resolution expects valid JavaScript code, but SVGs are written in XML. Here's where build tools like Webpack come in to help!

Import error

💡 For deeper insights of what’s going to happen further, i recommend watching this 10 min video Tech Talk: RegEx (SVG) & JSX: Adapting Vector Graphics for React. In my dev practice, i’ve done exactly this a couple of times before switching to webpack automation.

Webpack to the rescue!

Webpack can be configured to preprocess SVGs during the build process, transforming them into React components that you can easily use within your application. To achieve this, we'll leverage a package called @svgr/webpack.

Let’s edit webpack.config file to automatically transform svg into react component during build time. Install @svgr/webpack and follow usage guide.

// webpack.config.js

module: {
  rules: [
    {
      test: /\.svg$/i,
      issuer: /\.[jt]sx?$/,
      resourceQuery: { not: [/url/] }, // exclude react component if *.svg?url
      use: ["@svgr/webpack"],
    },
  ]
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • test: /\.svg$/i: This line tells Webpack to identify files ending with the .svg extension (case-insensitive).
  • issuer: /\.[jt]sx?$/: This line ensures the rule applies only when the SVG is imported within a JavaScript or TypeScript file (.js.jsx.ts, or .tsx).
  • resourceQuery: { not: [/url/] }: This line excludes SVGs used with the url() loader (used for embedding small SVGs directly in CSS).
  • use: ["@svgr/webpack"]: This line specifies the @svgr/webpack loader to handle SVG processing.

Using SVG Components:

Once Webpack processes your SVGs, you can import and use them as React components:

// src/App.js

import Logo from "path/to/logo.svg";
import "path/to/styles.css";

...

return (
  ...
  <Logo className="svg" />
  ...
)
Enter fullscreen mode Exit fullscreen mode

Styling SVG Components:

By transforming SVGs into React components using SVGR, you gain the ability to style the underlying SVG elements directly within your CSS.

// styles.css

.svg ellipse {
  stroke: red;
}
Enter fullscreen mode Exit fullscreen mode

This CSS code will target all ellipse elements within the Logo component you imported, making their stroke red.

Styling SVG Components

As you can see, SVGR processed our import making it possible to simple call it as function and pass props to it.

SVG optimisation with SVGR (utilising SVGO)

SVGR package uses SVGO to optimise SVG code before transforming it into react component. Utilising this may help you to dramatically reduce bundle size.

Refer to the configuration docs for available options or use both packages separately.

SVGs as Data URLs

This technique allows to store SVGs as strings using Data URL scheme, for example:

.some-div {
  background: url("data:image/svg+xml,<svg-string>");
}
Enter fullscreen mode Exit fullscreen mode

Refer to this helpful article Rendering SVGs as images directly in React

Advanced Topics. SVG Sprites

SVG sprites are a technique for combining multiple SVGs into a single image file. This can improve performance by reducing the number of HTTP requests needed to render multiple SVGs on a page. However, managing complex SVG sprites can become cumbersome.

Refer to this helpful article: Complete guide to SVG sprites

With webpack we can use svg-sprite-loader and it can be used in conjunction with other loaders like so:

// webpack.config.js v.4
const path = require("path");

module: {
  rules: [
    {
      test: /\\.svg$/,
      include: path.resolve(__dirname, "src"),
      loaders: [
        `svg-sprite-loader?${JSON.stringify({
          name: "[name].[hash]",
          prefixize: true,
        })}`,
        `svgo-loader?${JSON.stringify({
          plugins: [
            { removeTitle: true },
            { convertPathData: false },
            { removeUselessStrokeAndFill: true },
          ],
        })}`,
      ],
    },
 ]
}
Enter fullscreen mode Exit fullscreen mode

Further Resources:

Conclusion

By understanding the different approaches to using SVGs in React and leveraging tools like SVGR and Webpack, you can effectively integrate scalable vector graphics into your React applications. This guide has equipped you with the knowledge to:

  • Render SVGs as images or React components
  • Style SVG elements directly within your components
  • Optimize SVGs for better performance
  • Consider best practices and explore advanced techniques

I hope this guide empowers you to create visually appealing and performant React applications using SVGs!

Top comments (0)