Skip to content

Latest commit

 

History

History
610 lines (446 loc) · 19 KB

README.md

File metadata and controls

610 lines (446 loc) · 19 KB

svgr

Tranform SVG into React components 🦁

Build Status Code Coverage version MIT License

PRs Welcome Chat

Watch on GitHub Star on GitHub Tweet

Try it out online!

Watch the talk at React Europe

npm install svgr

Example

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

Motivation

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 are 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.

Command line usage

Usage: svgr [options] <file>

Options:

  -V, --version                    output the version number
  --ext <ext>                      specify a custom file extension (default: "js")
  --icon                           use "1em" as width and height
  --ids                            keep ids within the svg (svgo)
  --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)
  --keep-useless-defs              keep elements of <defs> without id (svgo)
  --native                         add react-native support with react-native-svg
  --no-bracket-spacing             print spaces between brackets in object literals (prettier)
  --no-dimensions                  remove width and height from root SVG tag
  --no-expand-props                disable props expanding
  --no-prettier                    disable Prettier
  --no-semi                        remove semi-colons (prettier)
  --no-svgo                        disable SVGO
  --no-title                       remove title tag (svgo)
  --no-view-box                    remove viewBox
  -d, --out-dir <dirname>          output files into a directory
  -p, --precision <value>          set the number of digits in the fractional part (svgo)
  --ref                            add svgRef prop to svg
  --replace-attr-value [old=new]   replace an attribute value
  --single-quote                   use single-quotes instead of double-quotes (prettier)
  --tab-width <value>              specify the number of spaces by indentation-level (prettier)
  --template <file>                specify a custom template to use
  --trailing-comma <none|es5|all>  print trailing commas wherever possible when multi-line (prettier)
  --use-tabs                       indent lines with tabs instead of spaces (prettier)
  -h, --help                       output usage information

Examples:
  svgr --replace-attr-value "#fff=currentColor" icon.svg

Recipes

Transform a whole directory

A whole directory can be processed, all SVG files (matching .svg or .SVG) are transformed into React components.

# Usage: svgr [-d out-dir] [src-dir]
$ 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

Use stdin

$ svgr < icons/web/wifi-icon.svg

Use stdin / stdout

$ svgr < icons/web/wifi-icon.svg > icons/web/WifiIcon.js

Transform icons

To create icons, two options are important:

  • --icon: title is removed, viewBox is preserved 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

Target React Native

It is possible to target React Native using react-native-svg.

$ svgr --native my-icon.svg

Use a specific template

You can use a specific template.

$ svgr --template path/to/template.js my-icon.svg

Example of template:

module.exports = (opts = {}) => {
  let props = ''

  if (opts.expandProps && opts.ref) {
    props = '{svgRef, ...props}'
  } else if (opts.expandProps) {
    props = 'props'
  } else if (opts.ref) {
    props = '{svgRef}'
  }

  return (code, state) => `import React from 'react'

const ${state.componentName} = (${props}) => ${code}

export default ${state.componentName}`
}

Node API usage

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, componentName: 'MyComponent' }).then(
  jsCode => {
    console.log(jsCode)
  },
)

Webpack usage

SVGR has a Webpack loader, you can use it using following webpack.config.js:

In your webpack.config.js:

{
  test: /\.svg$/,
  use: ['svgr/webpack'],
}

In your code:

import Star from './star.svg'

const App = () => (
  <div>
    <Star />
  </div>
)

Passing options

{
  test: /\.svg$/,
  use: [
    {
      loader: 'svgr/webpack',
      options: {
        native: true,
      },
    },
  ],
}

Using with url-loader or file-loader

It is possible to use it with url-loader or file-loader.

In your webpack.config.js:

{
  test: /\.svg$/,
  use: ['svgr/webpack', 'url-loader'],
}

In your code:

import starUrl, { ReactComponent as Star } from './star.svg'

const App = () => (
  <div>
    <img src={starUrl} alt="star" />
    <Star />
  </div>
)

Use your own Babel configuration

By default, svgr/webpack includes a babel-loader with optimized configuration. In some case you may want to apply a custom one (if you are using Preact for an example). You can turn off Babel transformation by specifying babel: false in options.

// Example using preact
{
  test: /\.svg$/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        presets: ['preact', 'env'],
      },
    },
    {
      loader: 'svgr/webpack',
      options: { babel: false },
    }
  ],
}

Handle SVG in CSS, Sass or Less

It is possible to detect the module that requires your SVG using Rule.issuer in Webpack. Using it you can specify two different configurations for JavaScript and the rest of your files.

{
  {
    test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
    issuer: {
      test: /\.jsx?$/
    },
    use: ['babel-loader', 'svgr/webpack', 'url-loader']
  },
  {
    test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
    loader: 'url-loader'
  },
}

Options

SVGR ships with a handful of customizable options, usable in both the CLI and API.

File extension

Specify a custom extension for generated files.

Default CLI Override API Override
"js" --ext ext: <string>

Icon

Replace SVG "width" and "height" value by "1em" in order to make SVG size inherits from text size. Also remove title.

Default CLI Override API Override
false --icon icon: <bool>

Ids

Setting this to true will keep ids. It can be useful to target specific ids using CSS or third party library (eg: react-mutate-icon).

Default CLI Override API Override
false --ids ids: <bool>

JSX Brackets

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>

Useless Defs

Keep elements of <defs> without id. It also keep unused symbols. See SVGO removeUselessDefs plugin.

Default CLI Override API Override
false --keep-useless-defs keepUselessDefs: <bool>

Native

Modify all SVG nodes with uppercase and use a specific template with react-native-svg imports. All unsupported nodes will be removed.

Default CLI Override API Override
false --native native: <bool>

Bracket Spacing

Print spaces between brackets in object literals. See Prettier.

Default CLI Override API Override
true --no-bracket-spacing bracketSpacing: <bool>

Dimensions

Remove width and height from root SVG tag.

Default CLI Override API Override
false --no-dimensions dimensions: <bool>

Expand props

All properties given to component will be forwarded on SVG tag.

Default CLI Override API Override
true --no-expand-props expandProps: <bool>

Prettier

Use Prettier to format JavaScript code output.

Default CLI Override API Override
true --no-prettier prettier: <bool>

Semicolons

Print semicolons at the ends of statements. See Prettier.

Default CLI Override API Override
true --no-semi semi: <bool>

SVGO

Use SVGO to optimize SVG code before transforming it into a component.

Default CLI Override API Override
true --no-svgo svgo: <bool>

Title

Setting this to false will remove the title from SVG. See SVGO removeTitle plugin.

Default CLI Override API Override
true --no-title title: <bool>

ViewBox

Setting this to false will remove the viewBox property.

Default CLI Override API Override
true --no-view-box viewBox: <bool>

Ref

Setting this to true will allow you to hook into the ref of the svg components that are created by exposing a svgRef prop

Default CLI Override API Override
false --ref ref: <bool>

Replace attribute value

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[[old, new]]>

Quotes

Use single quotes instead of double quotes. See Prettier.

Default CLI Override API Override
false --single-quote singleQuote: <bool>

Tab Width

Specify the number of spaces per indentation-level. See Prettier.

Default CLI Override API Override
2 --tab-width <int> tabWidth: <int>

Template

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>

Trailing Commas

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>"

Tabs

Indent lines with tabs instead of spaces. See Prettier.

Default CLI Override API Override
false --use-tabs useTabs: <bool>

Output Directory

Output files into a directory.

Default CLI Override API Override
undefined --out-dir <dirname> outDir: <dirname>

Precision

Set number of digits in the fractional part. See SVGO.

Default CLI Override API Override
3 --precision <int> precision: <int>

Other projects

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:

License

MIT