← Back to Recent PostsUsing SVGs in React

Using SVGs in React

January 20, 2023

I think it's safe to say that you're behind the times if you're not using SVGs for vector image assets like logos, icons, and decorative elements on your sites. After all, their benefits are plentiful and include:

  1. easy scaling without any loss of detail
  2. direct styling via CSS
  3. simple editing in any text editor (after all, SVGs are just made up of XML)

That said, they're not the easiest things to work with. Specifically, figuring out how to include them on your site can be kind of a pain because there are a bunch of different options.

In this post we'll explore:

Methods of Using SVGs

The two easiest and most common methods to include SVGs on a website are:

  • using an img tag
  • inlining the SVG code directly in the HTML of the site

Using an img Tag

You should use an img tag to include an SVG if: you want your SVGs managed via a CMS like WordPress; or you're writing a basic static site without any kind of templating engine or front-end framework. Using an img tag lets you keep track of your SVGs in a central location. You can update them at any time without having to worry about finding all the places you have used them throughout your site (that is, it keeps your code DRY).

<div class="svg-container">
  <img src="./path/to/your.svg" />
</div>

Inlining the SVG

However, my favorite way to use SVGs is to simply inline them in my markup. Doing it this way means it's incredibly easy to style and manipulate the SVG. Plus the SVG is embedded directly into the source code for your site. So you don't incur any extra network calls as you do when using an img tag.

Inlining SVGs directly in HTML is best when you either: only need to use the SVG once; or you are using some sort of templating engine or front-end framework to extract it its own component. If you need to use an SVG in multiple places but can't extract and import your SVG where you need it then you're probably better off using an img tag.

<div class="svg-container">
  <svg>
    <!-- SVG code goes here -->
  </svg>
</div>

Converting SVG Files to Valid JSX

Let's say we want to turn the following SVG image into a React component:

The source file looks like this:

our-image.svg
<?xml version="1.0"?>
<svg fill="#719BEC" fill-opacity="0.5" viewBox="0 0 500 500" width="250" height="250"
  xmlns="http://www.w3.org/2000/svg">
  <circle cx="250" cy="250" r="210" stroke="#000" strokeWidth="8"></circle>
</svg>

In order to use our source SVG as a React component we have to make sure it's valid JSX. As it stands, our source SVG element is not valid JSX. So we can't just open up the SVG file in a text editor, copy, and paste the SVG element into a .jsx or .tsx file.

Most of the problems I have run into trying to do so revolve around simple capitalization: an SVG element is just an HTML element and so generally prefers kebab-case (eg. clip-path and clip-rule); meanwhile JSX prefers camelCase (eg. clipPath and clipRule). In our source SVG file above we have a fill-opacity attribute; in JSX this should be fillOpacity. Additionally, our source SVG has an xml tag we won't need in our JSX.

These issues are simple enough to correct by hand with our small file. As we work with larger and more complex SVGs, though, the work is tedious and it's easy to miss a case or two.

SVG 2 JSX

Instead of converting SVGs to JSX by hand, I like to use a free tool called SVG 2 JSX. This tool takes in your SVG file and spits out valid JSX. It even wraps it in a functional component for you! All you need to do is copy the output text and plop it into a component file and you're ready to go. (Alternatively, you can just copy the svg element and plop it wherever you need in your existing JSX.)

Using a React Component

Once we have the icon component generated by SVG 2 JSX all we need to do is plop it into a component file. Once we do that we can use it anywhere we want just like it's a normal component (because it is!)

SVGIcon.tsx
import React from "react"

function Icon() {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="250"
      height="250"
      fill="#719BEC"
      fillOpacity="0.5"
      viewBox="0 0 500 500"
    >
      <circle cx="250" cy="250" r="210" stroke="#000"></circle>
    </svg>
  )
}

export default Icon

Improving the Our SVG Component

Our SVG graphic component is easy to use and reuse throughout our app, but it does have some problems as its currently implemented. Chief among them is that we have lost the ability to interact with the SVG HTML element. As you can see, width and height are hard-coded into the SVG, meaning it'll always be 250px by 250px. This is easily solved though.

To make our component behave more like a wrapper for the SVG element it returns we need to make it behave like a wrapper. All we need to do this is to pass all props given to our wrapper to the SVG HTML element. In TypeScript this looks like:

SVGIcon.tsx
import React from "react"

// TypeScript: type the props to be the same as a normal SVG element
function Icon(props: React.ComponentProps<"svg">) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="250"
      height="250"
      fill="#719BEC"
      fillOpacity="0.5"
      viewBox="0 0 500 500"

      // Expand given props last to overwrite existing attributes
      // This let's us pass arbitrary values
      {...props}
    >
      <circle cx="250" cy="250" r="210" stroke="#000"></circle>
    </svg>
  )
}

export default Icon

Now we can use our icon component anywhere and have control over the SVG HTML element it will spit out. For instance, that width and height problem I mentioned before won't be a problem anymore:

app.ts
import Icon from './SVGIcon'

const App = (props) => (
  <div>
    // These width and height values will overwrite the values in SVGIcon.tsx
    <Icon width="500" height="500" />
  </div>
)

export default App

We can even use tailwind directly on it, if that's our thing:

app.ts
import Icon from './SVGIcon'

const App = (props) => (
  <div>
    <Icon
      width="500"
      height="500"
      className="fill-blue-500"
    />
  </div>
)

export default App

Conclusion

This post has explored: common methods for using SVGs on websites, how to easily convert a given SVG file into valid JSX, and how to effectively use that JSX within a reusable wrapper component in React. Be sure to check out SVG 2 JSX. It is one of my favorite tools and saves me quite a bit of time and mental energy. Hopefully it will help you as much as it has me!