Composable SVGs in React

The modern web has taught us that using SVGs is a good idea; they scale well on all screen sizes, they have fairly small file sizes, and can be edited easily with CSS. However, using them in a modern single-page app is a bit of a pain. To be piped through Webpack, they need a special loader, and often custom SVG components for libraries like React. And while it’s still possible to change the style (colour, size, etc) of the imported SVGs, it’s a little cumbersome. There must be a better way.

SVGs are just text files; they are written in XML. When I saw this for the first time, it got me thinking; I’m writing HTML (as JSX) to create React components - why can I not just use SVGs as React components too? So I opened an SVG in my browser, broke open the devtools and copied and pasted the HTML into a new React component, like this:

import React from 'react'

const Icon = ({}) => (
  <svg style="width: 32px; height: 32px;">
    …
  </svg>
)

export default Icon

You can then simply import this into another React component and use as you would any other component.

So this is great. By doing this, we’re reducing the number of requests that need to be made by the browser, and including the code straight in our bundled app.

However, we still haven’t made it much easier to modify; you’d still need to use some fiddly CSS to achieve that. But hold on. As this is now a standard React component, we can pass props to it. Like this:

import React from 'react'

const Icon = ({ color = '#ff0000' }) => (
  <svg style="width: 32px; height: 32px;">
    <g fill={color}></g>
  </svg>
)

export default Icon

Also, we can use styled-components to remove the ugly inline styling:

import React from 'react'
import styled from 'styled-components'

const SVG = styled.svg`
    width: ${props => props.size}px;
  height: ${props => props.size}px;
`

const Icon = ({ color = '#ff0000', size = 32 }) => (
  <Svg size={size}>
    <g fill={color}></g>
  </svg>
)

export default Icon

We now have a composable, re-usable SVG component. Happy days.