Tuesday, March 21, 2023
HomeReactuse SVG Icons as React Elements

use SVG Icons as React Elements


I at all times struggled to make use of SVG in my React functions. Each time I searched concerning the matter on-line, I’ve discovered some ways on easy methods to use SVG in React, however as soon as I applied the approaches, the success charges have been very low. At present I need to offer you an easy strategy on easy methods to use SVG icons as React elements on your subsequent React utility.

Observe: All icons used on this tutorial are from Flaticon. For those who use icons from there, do not forget to attribute the authors/platform.

It is doable to have one folder in your React utility that holds all of your .svg recordsdata on your icons. From there, you may generate your React elements manually/routinely. I’ll present you each approaches within the subsequent two sections for creating icon elements manually together with your command line interface and npm scripts, but additionally for creating your icon elements routinely with Webpack. The instrument we’re utilizing known as SVGR which is extensively used (e.g. create-react-app).

Desk of Contents

React SVG Icon Elements from CLI

On this part, we are going to begin by producing SVG icons manually on your React utility. For those who want a starter undertaking, head over to this Webpack + Babel + React undertaking and comply with the set up directions.

Subsequent, put all of your .svg icon recordsdata right into a /property folder subsequent to your src/ folder. We do not need to have the property blended with our supply code recordsdata, as a result of we are going to generate JavaScript recordsdata based mostly on them. These JavaScript recordsdata — being React icon elements — are blended together with your different supply code recordsdata then.

property/

-- twitter.svg

-- fb.svg

-- github.svg

src/

-- index.js

-- App.js

Now, create an empty src/Icons/ folder for all of your generated React icon elements:

property/

-- twitter.svg

-- fb.svg

-- github.svg

src/

-- index.js

-- App.js

-- Icons/

The specified final result can be to make use of the React icon elements in our src/App.js element:

import React from 'react';

import TwitterIcon from './Icons/Twitter.js';

import FacebookIcon from './Icons/Fb.js';

import GithubIcon from './Icons/Github.js';

const App = () => (

<div>

<ul>

<li>

<TwitterIcon width="40px" peak="40px" />

<a href="https://twitter.com/rwieruch">Twitter</a>

</li>

<li>

<FacebookIcon width="40px" peak="40px" />

<a href="https://www.fb.com/rwieruch/">Fb</a>

</li>

<li>

<GithubIcon width="40px" peak="40px" />

<a href="https://github.com/rwieruch">Github</a>

</li>

</ul>

</div>

);

export default App;

Nevertheless, this does not work but as a result of the src/Icons/ folder is empty. There aren’t any icon elements but. Within the subsequent step, the property/ folder will act as supply folder and the src/Icons/ as goal folder. We’ll add a brand new npm script to our bundle.json file which is able to generate the React icon elements:

{

...

"foremost": "index.js",

"scripts": {

"svgr": "svgr -d src/Icons/ property/",

"begin": "webpack serve --config ./webpack.config.js --mode improvement"

},

"key phrases": [],

...

}

Final however not least, set up the SVGR CLI bundle on the command line:

npm set up @svgr/cli --save-dev

Now, after having all the things arrange correctly, you may execute your new npm script with npm run svgr on the command line. Studying the command line output, you may see that new JavaScript recordsdata are being generated out of your svg recordsdata. After the command terminates, it is best to have the ability to see the svg icons rendered as React elements when beginning your utility. It’s also possible to examine your src/Icons folder to see all generated React icon elements. They take as effectively, which makes it doable for us to outline their peak and width.

That is all it must generate React elements from SVGs. Each time you will have a brand new SVG file or alter one among your present SVG recordsdata, you may the npm run svgr command once more.

React SVG Icon Elements from Webpack

Working the SVGR script each time to replace your SVG icons will not be one of the best resolution although. What about integrating the entire course of in your Webpack configuration? It’s best to begin out with an empty src/Icons folder. Afterward, transfer all of your SVG recordsdata to this folder and take away the property/ folder. Your folder construction ought to seem like the next:

src/

-- index.js

-- App.js

-- Icons/

---- twitter.svg

---- fb.svg

---- github.svg

Your App element imports SVG recordsdata slightly than JavaScript recordsdata now:

import React from 'react';

import TwitterIcon from './Icons/Twitter.svg';

import FacebookIcon from './Icons/Fb.svg';

import GithubIcon from './Icons/Github.svg';

const App = () => (

<div>

<ul>

<li>

<TwitterIcon width="40px" peak="40px" />

<a href="https://twitter.com/rwieruch">Twitter</a>

</li>

<li>

<FacebookIcon width="40px" peak="40px" />

<a href="https://www.fb.com/rwieruch/">Fb</a>

</li>

<li>

<GithubIcon width="40px" peak="40px" />

<a href="https://github.com/rwieruch">Github</a>

</li>

</ul>

</div>

);

export default App;

Beginning your utility would not work, as a result of we can’t merely import SVG recordsdata this manner. Luckily, we will make Webpack doing the work for us implicitly with each utility begin. Let’s add the next configuration to our webpack.config.js file:

const path = require('path');

const webpack = require('webpack');

module.exports = {

entry: path.resolve(__dirname, './src/index.js'),

module: {

guidelines: [

jsx)$/,

exclude: /node_modules/,

use: ['babel-loader'],

,

{

take a look at: /.svg$/,

use: ['@svgr/webpack'],

},

],

},

...

};

Afterward, set up the mandatory Webpack bundle for SVGR:

npm set up @svgr/webpack --save-dev

When you begin your utility, Webpack is doing its factor and also you need not fear about your SVGs anymore. You’ll be able to put your SVG recordsdata anyplace in your src/ folder and import them wherever you want them as React elements. There isn’t any want anymore for the SVGR npm script in your bundle.json file which now we have applied within the earlier part.

Various: react-svg-loader

In case you are utilizing Webpack, you can too use a simplified SVG loader as a substitute of SVGR. As an example, react-svg-loader can be utilized inside your Webpack configuration. Observe that it replaces SVGR:

const path = require('path');

const webpack = require('webpack');

module.exports = {

entry: path.resolve(__dirname, './src/index.js'),

module: {

guidelines: [

jsx)$/,

exclude: /node_modules/,

use: ['babel-loader'],

,

{

loader: 'react-svg-loader',

choices: {

jsx: true

}

}

],

},

...

};

Additionally it’s essential to set up it:

npm set up react-svg-loader --save-dev

Afterward, you may import SVG recordsdata the identical means as React elements as you probably did earlier than with SVGR. It may be seen as a light-weight various to SVGR.

SVGR Templates for superior SVGs

After I labored with my final shopper on their React utility, I had the issue of coping with SVG icons which had solely partially the viewBox attribute. Since this attribute is required for giving your SVG icons a dimension, I needed to discover a means round to introduce this attribute every time it wasn’t current for an icon. Now I might undergo each SVG icon to repair this challenge, nonetheless, coping with greater than 500 icons would not make this a cushty job. Let me present how I handled it by utilizing SVGR templates as a substitute.

The default SVGR template in your webpack.config.js file appears like the next:

...

module.exports = {

entry: path.resolve(__dirname, './src/index.js'),

module: {

guidelines: [

jsx)$/,

exclude: /node_modules/,

use: ['babel-loader'],

,

{

take a look at: /.svg$/,

use: [

{

loader: '@svgr/webpack',

options: {

template: (

{ template },

opts,

{ imports, componentName, props, jsx, exports }

) => template.ast`

${imports}

const ${componentName} = (${props}) => {

return ${jsx};

};

export default ${componentName};

`,

},

},

],

},

],

},

...

};

By having this template at your disposal, you may change the code which is generated from the SVG file. To illustrate we need to fill all our icons with a blue coloration. We simply lengthen the props object with a fill attribute:

...

module.exports = {

entry: path.resolve(__dirname, './src/index.js'),

module: {

guidelines: [

jsx)$/,

exclude: /node_modules/,

use: ['babel-loader'],

,

{

take a look at: /.svg$/,

use: [

{

loader: '@svgr/webpack',

options: {

template: (

{ template },

opts,

{ imports, componentName, props, jsx, exports }

) => template.ast`

${imports}

const ${componentName} = (${props}) => {

props = { ...props, fill: 'blue' };

return ${jsx};

};

export default ${componentName};

`,

},

},

],

},

],

},

...

};

This could work to present all icons a blue fill attribute. Nevertheless, easy use instances like this are already offered by SVGR itself. Simply take a look at their documentation on easy methods to add/change/take away attribute from SVGs.

SVGR with customized viewBox attribute

In our case, we needed to compute the viewBox attribute for each SVG icon the place the attribute is not current. First, take away the viewBox attribute from one among your SVGs to see that it isn’t rendered correctly anymore. After confirming the bug, we are going to attempt to repair it by utilizing the launched SVGR template and an exterior :

import React from 'react';

const useWithViewbox = ref => {

React.useLayoutEffect(() => {

if (

ref.present !== null &&

!ref.present.getAttribute('viewBox') &&

ref.present.getBBox &&

ref.present.getBBox().width &&

ref.present.getBBox().peak

) {

const field = ref.present.getBBox();

ref.present.setAttribute(

'viewBox',

[box.x, box.y, box.width, box.height].be a part of(' ')

);

}

});

};

export default useWithViewbox;

The React hook solely wants a reference (ref) to the SVG elements with a purpose to set the viewBox attribute. The measurements for the viewBox attribute are computed based mostly on the rendered icon. If the icon hasn’t been rendered or the viewBox attribute is already current, we do nothing.

The hook ought to be someplace obtainable not distant from our src/Icons/ folder:

src/

-- index.js

-- App.js

-- useWithViewbox.js

-- Icons/

---- twitter.svg

---- fb.svg

---- github.svg

Now, we will use the hook for our SVG template within the webpack.config.js file:

...

module.exports = {

entry: path.resolve(__dirname, './src/index.js'),

module: {

guidelines: [

...

{

test: /.svg$/,

use: [

{

loader: '@svgr/webpack',

options: {

template: (

{ template },

opts,

{ imports, componentName, props, jsx, exports }

) => template.ast`

${imports}

import useWithViewbox from '../useWithViewbox';

const ${componentName} = (${props}) => {

const ref = React.useRef();

useWithViewbox(ref);

props = { ...props, ref };

return ${jsx};

};

export default ${componentName};

`,

},

},

],

},

],

},

...

};

Having this in place, SVGR’s template characteristic will add the customized hook to each generated icon element. The hook solely runs for icon elements which haven’t any viewBox attribute although. For those who run your utility once more, it is best to see all icon elements rendered correctly, despite the fact that you could have eliminated the viewBox attribute from one among them.


Ultimately, I hope this walkthrough has helped you to get began with SVG icons in React by utilizing SVGR together with your command line/npm scripts or Webpack. The completed utility utilizing the Webpack strategy and React could be discovered on this GitHub repository. For those who run into any bugs, let me know within the feedback. In any other case I’m joyful to heard about your particular use instances which fall into the class of my lacking viewBox bug. Let me find out about these instances within the feedback.



RELATED ARTICLES

Most Popular

Recent Comments