Tranform SVG into React components 🦁
npm install svgr
Take an icon.svg:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48px" height="1px" viewBox="0 0 48 1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Rectangle 5</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="19-Separator" transform="translate(-129.000000, -156.000000)" fill="#063855">
<g id="Controls/Settings" transform="translate(80.000000, 0.000000)">
<g id="Content" transform="translate(0.000000, 64.000000)">
<g id="Group" transform="translate(24.000000, 56.000000)">
<g id="Group-2">
<rect id="Rectangle-5" x="25" y="36" width="48" height="1"></rect>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
Run SVGR
svgr --no-semi --icon --replace-attr-value "#063855=currentColor" icon.svg
Output
import React from "react"
const SvgComponent = props => (
<svg width="1em" height="1em" viewBox="0 0 48 1" {...props}>
<path d="M0 0h48v1H0z" fill="currentColor" fillRule="evenodd" />
</svg>
)
export default SvgComponent
React supports SVG out of the box, it's simpler, easier and much more powerful to have components instead of SVG files. Wrapped in a React component, your SVG is inlined in the page and you can style it using CSS.
There is a lot of similar projects but I wanted something more solid and configurable. SVGR is based on h2x, a powerful and configurable HTML transpiler. It uses AST (like Babel) that gives a lot of power.
Usage: svgr [options] <file>
Options:
-V, --version output the version number
-d, --out-dir <dirname> output files into a directory
--no-svgo disable SVGO
--no-prettier disable Prettier
--template <file> specify a custom template to use
--no-expand-props disable props expanding
--icon use "1em" as width and height
--replace-attr-value [old=new] replace an attribute value
-p, --precision <value> set the number of digits in the fractional part (svgo)
--no-title remove title tag (svgo)
--tab-width specify the number of spaces by indentation-level (prettier)
--use-tabs indent lines with tabs instead of spaces (prettier)
--no-semi remove semi-colons (prettier)
--single-quote use single-quotes instead of double-quotes (prettier)
--trailing-comma <none|es5|all> print trailing commas wherever possible when multi-line (prettier)
--no-bracket-spacing print spaces between brackets in object literals (prettier)
--jsx-bracket-same-line put the > of a multi-line JSX element at the end of the last line instead of being alone on the next line (prettier)
-h, --help output usage information
Examples:
svgr --replace-attr-value "#fff=currentColor" icon.svg
A whole directory can be processed, all SVG files (matching .svg
or .SVG
)
are transformed into React components.
$ svgr -d icons icons
icons/web/clock-icon.svg -> icons/web/ClockIcon.js
icons/web/wifi-icon.svg -> icons/web/WifiIcon.js
icons/spinner/cog-icon.svg -> icons/spinner/CogIcon.js
icons/spinner/spinner-icon.svg -> icons/spinner/SpinnerIcon.js
$ svgr < icons/web/wifi-icon.svg
$ svgr < icons/web/wifi-icon.svg > icons/web/WifiIcon.js
To create icons, two options are important:
--icon
: title is removed and SVG inherits text size--replace-attr-value "#000000=currentColor"
: "#000000" is replaced by "currentColor" and SVG inherits text color
$ svgr --icon --replace-attr-value "#000000=currentColor" my-icon.svg
You can use a specific template, for an example of template, see the default one.
$ svgr --template path/to/template.js my-icon.svg
SVGR can also be used programmatically:
import svgr from 'svgr'
const svgCode = `
<?xml version="1.0" encoding="UTF-8"?>
<svg width="88px" height="88px" viewBox="0 0 88 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Dismiss</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Blocks" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="square">
<g id="Dismiss" stroke="#063855" stroke-width="2">
<path d="M51,37 L37,51" id="Shape"></path>
<path d="M51,51 L37,37" id="Shape"></path>
</g>
</g>
</svg>
`
svgr(svgCode, { prettier: false }).then(jsCode => {
console.log(jsCode)
})
SVGR has a Webpack loader, you can use it using following webpack.config.js
:
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
use: ['svgr/webpack', 'babel-loader']
}
]
}
}
It is also possible to specify options:
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
use: [
{
loader: 'svgr/webpack',
options: {
svgo: false
}
},
'babel-loader',
]
}
]
}
}
SVGR ships with a handful of customizable options, usable in both the CLI and API.
Use SVGO to optimize SVG code before transforming it into a component.
Default | CLI Override | API Override |
---|---|---|
true |
--no-svgo |
svgo: <bool> |
Use Prettier to format JavaScript code output.
Default | CLI Override | API Override |
---|---|---|
true |
--no-prettier |
prettier: <bool> |
Specify a template file (CLI) or a template function (API) to use. For an example of template, see the default one.
Default | CLI Override | API Override |
---|---|---|
wrapIntoComponent |
--template |
template: <func> |
All properties given to component will be forwarded on SVG tag.
Default | CLI Override | API Override |
---|---|---|
true |
--no-expand-props |
expandProps: <bool> |
Remove title and replace SVG "width" and "height" value by "1em" (SVG size inherits from text size).
Default | CLI Override | API Override |
---|---|---|
false |
--icon |
icon: <bool> |
Replace an attribute value by an other. The main usage of this option is to change an icon color to "currentColor" in order to inherit from text color.
Default | CLI Override | API Override |
---|---|---|
[] |
--replace-attr-value <old=new> |
replaceAttrValues: <string[]> |
Set number of digits in the fractional part. See SVGO.
Default | CLI Override | API Override |
---|---|---|
3 |
--precision <int> |
precision: <int> |
Remove the title from SVG. See SVGO removeTitle
plugin.
Default | CLI Override | API Override |
---|---|---|
true |
--no-title |
title: <bool> |
Specify the number of spaces per indentation-level. See Prettier.
Default | CLI Override | API Override |
---|---|---|
2 |
--tab-width <int> |
tabWidth: <int> |
Indent lines with tabs instead of spaces. See Prettier.
Default | CLI Override | API Override |
---|---|---|
false |
--use-tabs |
useTabs: <bool> |
Print semicolons at the ends of statements. See Prettier.
Default | CLI Override | API Override |
---|---|---|
true |
--no-semi |
semi: <bool> |
Use single quotes instead of double quotes. See Prettier.
Default | CLI Override | API Override |
---|---|---|
false |
--single-quote |
singleQuote: <bool> |
Print trailing commas wherever possible when multi-line. See Prettier.
Default | CLI Override | API Override |
---|---|---|
"none" |
--trailing-comma <none|es5|all> |
trailingComma: "<none|es5|all>" |
Print spaces between brackets in object literals. See Prettier.
Default | CLI Override | API Override |
---|---|---|
true |
--no-bracket-spacing |
bracketSpacing: <bool> |
Put the >
of a multi-line JSX element at the end of the last line instead of
being alone on the next line (does not apply to self closing elements). See Prettier.
Default | CLI Override | API Override |
---|---|---|
false |
--jsx-bracket-same-line |
jsxBracketSameLine: <bool> |
A lot of projects tried to solve this problem, unfortunately, none of them fulfills my use cases.
Using raw node:
Using command line:
Or using a Webpack loader:
Or using a browserify loader:
Or using gulp / grunt plugin:
Or at runtime:
Or using grunt:
MIT