olefrank
olefrank

Reputation: 6810

Inline SVG in react 16

I have a SVG file that I want to use as an icon in my react component.

<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 409.6 405.76"><defs><style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style><clipPath id="clip-path" transform="translate(-478 -181.08)"><rect class="cls-1" x="478" y="181" width="409.92" height="406.8"/></clipPath></defs><title>test</title><g class="cls-2"><path class="ofj" d="M682.8,396.06c50.72,0,91.84-48.13,91.84-107.49,0-82.33-41.12-107.49-91.84-107.49S591,206.24,591,288.57c0,59.36,41.12,107.49,91.84,107.49Zm0,0" transform="translate(-478 -181.08)"/><path d="M885.6,554.28,839.27,449.9a23.3,23.3,0,0,0-10.48-11.15l-71.91-37.43a4.66,4.66,0,0,0-4.93.41,113.41,113.41,0,0,1-138.3,0,4.67,4.67,0,0,0-4.94-.41l-71.9,37.43a23.24,23.24,0,0,0-10.47,11.15L480,554.28a23.16,23.16,0,0,0,21.18,32.56H864.42a23.17,23.17,0,0,0,21.18-32.56Zm0,0" transform="translate(-478 -181.08)"/></g></svg>

I want to be able to change the fill color dynamically. I've read that it's best to use SVG 'inline' and I tried to reference it with a <use> but it does not work (it's not showing...)

<svg className="icon-avator">
  <use xlinkHref="./assets/avatar.svg" />
</svg>

How can I achieve this?

Upvotes: 8

Views: 21150

Answers (4)

Brad Vanderbush
Brad Vanderbush

Reputation: 169

There is also a npm package that converts all svg elements to the correct JSX incase anyone else came here and stumbled with a similar problem.

https://www.npmjs.com/package/convert-svg-react

Upvotes: 1

Denis Zhbankov
Denis Zhbankov

Reputation: 1179

Another option is to not use an external source, so instead of doing

<use href="/path/to/icon.svg" />

create a sprite with symbols (e.g. with https://www.npmjs.com/package/svg-sprite) like that:

<svg ...>
  // icon contents here, except `svg` tag became `symbol` tag
  <symbol id="icon-id-inside-the-sprite" ...>
    // ...
  </symbol>
  // may be add more icons
</svg>

inline it into your HTML somewhere and hide with display: none style, then use it like

<use href="#icon-id-inside-the-sprite" />

Now you should be able to target its inner classes from your outside CSS.

Upvotes: 0

3Dos
3Dos

Reputation: 3487

For people landing on this page, there is also a webpack loader which generates React components from SVG files. react-svg-loader

If you are using create-react-app, you might want to eject for now. But know this; there are discussions about integrating such a loader in CRA and it's on the 2.0.0 roadmap apparently

Upvotes: 2

Ori Drori
Ori Drori

Reputation: 191976

React JSX can produce SVG, the same way it does with HTML. Write the SVG as the component's "markup", and use props to control the fill attribute (you can also change the style):

const Icon = ({ fill }) => (
  <svg viewBox="0 0 409.6 405.76" fill={ fill }>
      <path d="M682.8,396.06c50.72,0,91.84-48.13,91.84-107.49,0-82.33-41.12-107.49-91.84-107.49S591,206.24,591,288.57c0,59.36,41.12,107.49,91.84,107.49Zm0,0" transform="translate(-478 -181.08)"/>
      <path d="M885.6,554.28,839.27,449.9a23.3,23.3,0,0,0-10.48-11.15l-71.91-37.43a4.66,4.66,0,0,0-4.93.41,113.41,113.41,0,0,1-138.3,0,4.67,4.67,0,0,0-4.94-.41l-71.9,37.43a23.24,23.24,0,0,0-10.47,11.15L480,554.28a23.16,23.16,0,0,0,21.18,32.56H864.42a23.17,23.17,0,0,0,21.18-32.56Zm0,0" transform="translate(-478 -181.08)"/>
  </svg>
);

ReactDOM.render(
  <Icon fill="red" />,
  demo
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="demo"></div>

Upvotes: 11

Related Questions