138

So normally to include most of my SVG icons that require simple styling, I do:

<svg>
    <use xlink:href="/svg/svg-sprite#my-icon" />
</svg>

Now I have been playing with ReactJS as of late evaluating it as a possible component in my new front-end development stack however I noticed that in its list of supported tags/attributes, neither use or xlink:href are supported.

Is it possible to use svg sprites and load them in this way in ReactJS?

ryanzec
  • 27,284
  • 38
  • 112
  • 169
  • 41
    For future visitors, you can now use ``. – David Gilbertson Nov 15 '16 at 21:56
  • 9
    `xlink:href` is deprecated, now supposed to just use `href` -- https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href – Matt Greer Nov 23 '17 at 18:50
  • 2
    @MattGreer As of 2018, Safari still needs `xlink:href` so we still need to use it. Actual web applications need to either use the common denominator of browser features, or implement specific workarounds / polyfills. – Tobia Feb 27 '18 at 09:54
  • I'm just adding this comment to help others who search for this error, which was solved by Jon Surrell's answer below: `Property 'xlink' does not exist on type 'SVGProps` – Joe M Oct 12 '18 at 18:35
  • Hey, maybe accept a different answer? Community seems to be agreed about that. Just a helpful suggestion, thanks. – HoldOffHunger Aug 02 '21 at 13:21

7 Answers7

311

MDN says that xlink:href is deprecated in favor of href. You should be able to use the href attribute directly. The example below includes both versions.

As of React 0.14, xlink:href is available via React as the property xlinkHref. It is mentioned as one of the "notable enhancements" in the release notes for 0.14.

<!-- REACT JSX: -->
<svg>
  <use xlinkHref='/svg/svg-sprite#my-icon' />
</svg>

<!-- RENDERS AS: -->
<svg>
  <use xlink:href="/svg/svg-sprite#my-icon"></use>
</svg>

Update 2018-06-09: Added info about href vs xlink:href attributes and updated example to include both. Thanks @devuxer

Update 3: At time of writing, React master SVG properties can be found here.

Update 2: It appears that all svg attributes should now be available via react (see merged svg attribute PR).

Update 1: You may want to keep an eye on the svg related issue on GitHub for additional SVG support landing. There are developments in the works.

Demo:

const svgReactElement = (
  <svg
    viewBox="0 0 1340 667"
    width="100"
    height="100"
  >
    <image width="667" height="667" href="https://i.imgur.com/w7GCRPb.png"/>
    { /* Deprecated xlink:href usage */ }
    <image width="667" height="667" x="673" xlinkHref="https://i.imgur.com/w7GCRPb.png"/>
  </svg>
);

var resultHtml = ReactDOMServer.renderToStaticMarkup(svgReactElement);
document.getElementById('render-result-html').innerHTML = escapeHtml(resultHtml);

ReactDOM.render(svgReactElement, document.getElementById('render-result') );

function escapeHtml(unsafe) { return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.1/umd/react-dom-server.browser.development.js"></script>

<h2>Render result of rendering:</h2>
<pre>&lt;svg
  viewBox=&quot;0 0 1340 667&quot;
  width=&quot;100&quot;
  height=&quot;100&quot;
&gt;
  &lt;image width=&quot;667&quot; height=&quot;667&quot; href=&quot;https://i.imgur.com/w7GCRPb.png&quot;/&gt;
  { /* Deprecated xlink:href usage */ }
  &lt;image width=&quot;667&quot; height=&quot;667&quot; x=&quot;673&quot; xlinkHref=&quot;https://i.imgur.com/w7GCRPb.png&quot;/&gt;
&lt;/svg&gt;</pre>

<h2><code>ReactDOMServer.renderToStaticMarkup()</code> output:</h2>
<pre id="render-result-html"></pre>
<h2><code>ReactDOM.render()</code> output:</h2>
<div id="render-result"></div>
Jon Surrell
  • 9,444
  • 8
  • 48
  • 54
  • 2
    > Update 25 Dec 2015: It appears that all svg attributes should now be available via react (see merged svg attribute PR). Is there a standard way to use these svg attributes? Will they all be camel cased like in the case of xlink:href => xlinkHref ? – tnrich Feb 24 '16 at 23:01
  • @majorBummer take a look [here](https://github.com/facebook/react/blob/dff05beeff9562647950461830ce42d484ca55fa/src/renderers/dom/shared/SVGDOMPropertyConfig.js#L58-L83) – Jon Surrell Feb 25 '16 at 09:52
  • 2
    this really needs to be the correct answer, especially when the current chosen answer recommends dangerouslySetInnerHTML, which is, well, dangerous – feihcsim Nov 02 '17 at 00:39
  • 1
    According to MDN (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href), `xlink:href` has been deprecated, and the recommendation is to use `href` without the namespace prefix. (Note, however, if you're using TypeScript, the typings haven't yet been updated to reflect this.) – devuxer Jun 16 '18 at 00:48
  • At the time of writing, xlink:href is supported in Safari, but href is not. – neoncube Sep 20 '18 at 04:07
  • `` has been working for me so far, but not sure what side affect it will have with each browser when they drop it. Hopefully they will just ignore it. – talves Dec 02 '18 at 20:34
  • xlink:href deprecated for SVG 2.0, but it is still a work in progress with no full browser implementation, also old browsers do not support SVG 2 – Andrey Izman Feb 05 '19 at 15:00
52

Update september 2018: this solution is deprecated, read Jon’s answer instead.

--

React doesn’t support all SVG tags as you say, there is a list of supported tags here. They are working on wider support, f.ex in this ticket.

A common workaround is to inject HTML instead for non-supported tags, f.ex:

render: function() {
    var useTag = '<use xlink:href="/svg/svg-sprite#my-icon" />';
    return <svg dangerouslySetInnerHTML={{__html: useTag }} />;
}
David Hellsing
  • 106,495
  • 44
  • 176
  • 212
10

If you encounter xlink:href, then you can get the equivalent in ReactJS by removing the colon and camelcasing the added text: xlinkHref.

You'll probably eventually be using other namespace-tags in SVG, like xml:space, etc.. The same rule applies to them (i.e., xml:space becomes xmlSpace).

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
6

As already said in Jon Surrell's answer, use-tags are supported now. If you are not using JSX, you can implement it like this:

React.DOM.svg( { className: 'my-svg' },
    React.createElement( 'use', { xlinkHref: '/svg/svg-sprite#my-icon' }, '' )
)
mwiegboldt
  • 2,682
  • 2
  • 16
  • 22
3

I created a little helper that works around this issue: https://www.npmjs.com/package/react-svg-use

first npm i react-svg-use -S then simply

import Icon from 'react-svg-use'

React.createClass({
  render() {
    return (
      <Icon id='car' color='#D71421' />
    )
  }
})

and this will then generate the following markup

<svg>
  <use xlink:href="#car" style="fill:#D71421;"></use>
</svg>
Ahrengot
  • 1,579
  • 1
  • 17
  • 29
0

I had problems with showing SVG in Gutenberg block, by referencing it with xlink:href. We used xlinkHref property in react, but after compiling, instead to render as xlink:href it was rendered to xlinkhref, and SVG was not displayed. After a lot of examining, I found out that xlink:href is deprecated (although it worked if we add it in html, or directly in chrome dev tools), and that href should be used instead. So after changing it to href it worked.

"SVG 2 removed the need for the xlink namespace, so instead of xlink:href you should use href." https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href

This is the code I used

SVG file

<svg id="svg-source" style="display: none;" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
    <symbol id="svg-arrow-accordion" viewBox="0 0 15 24" fill="none">
        <path id="Path_1662" data-name="Path 1662" d="M15.642,14.142h-3V1.5H0v-3H15.642Z" transform="translate(2 2) rotate(45)" fill="currentColor"></path>
    </symbol>
</svg>

React file

<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="15" height="24">
<use href="#svg-arrow-accordion"></use>
</svg>
emir
  • 1,336
  • 1
  • 14
  • 33
0

This is svg Component.

const SvgComponent = () => {
    return <svg width="0" height="0">
        <defs>
            <symbol id="test" viewBox="0 0 100 100">
                <line x1='0' y1='50' x2='100' y2='50' strokeWidth='8' stroke="#000" />
            </symbol>
        </defs>
    </svg>
}

export default SvgComponent

use component

import SvgComponent from './SvgComponent';

export default function App() {
  return (
    <>
      <SvgComponent/>
      <svg>
        <use xlinkHref="#test"></use>
      </svg>
    </>
  );
}
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 06 '22 at 07:02