Telion
Telion

Reputation: 777

Fill for external SVG file in React

It doesn't seem to be possible so far to control the SVG elements that are stored in a separate file. I thought maybe with WebPack and npm modules it should be possible yet can't find a simple or convenient solution. Is it possible to import element like this?

import icon from "./icons/user.svg"

<icon fill="red" />

I don't understand why it is so hard to work with SVG here, or why can't I find enough information on the topic. Maybe I am doing this wrong? Are there better ways to manage a lot of icons for a React website? I need will be using quite a few, like social networks stuff and similar.

Upvotes: 4

Views: 15428

Answers (5)

Grgur
Grgur

Reputation: 7382

If you use Create React App, then the easiest solution is to import SVG as a React component

import { ReactComponent as User } from './icons/user.svg';

const View = () => <User />;

See more in the docs: https://facebook.github.io/create-react-app/docs/adding-images-fonts-and-files#adding-svgs

Upvotes: 4

Ghis
Ghis

Reputation: 913

I know I looks a bit struggling, but here is the best solution I could end up with : Use webpack file-loader to get the url of your svg and use it as a css mask on which you can apply a background color and some sizing options :

const name = 'chevron-up';
const size = 16;
const url = require(`!file-loader!../../../vendor/my-icons/icons/${name}.svg`);

return
  <span style={{
    height: size,
    width: size,
    display: 'inline-block',
    backgroundColor: backgroundColor || 'black',
    WebkitMask: `url('${url}') no-repeat 50% 50% / cover`,
    mask: `url('${url}') no-repeat 50% 50% / cover`,
  }} />
;

It has a couple compatibility isssues for now, but it is supported by most latest browsers. So I guess we should embrace the future my friend !

https://developer.mozilla.org/fr/docs/Web/CSS/mask

Upvotes: 0

nick
nick

Reputation: 688

Include an external SVG image with four lines of code:

<svg>
  <use xlinkHref={'/images/logo.svg#Version-2'}>
  </use>
</svg>

In this case the SVG image "logo.svg" will have an ID in it named: "Version-2". The part after the hash "#" maps to an ID in the SVG image that must of course exist.

Upvotes: 2

Muhammad Adeel
Muhammad Adeel

Reputation: 2884

I would suggest to keep the code simple and treat SVG as a HTML. This way you avoid resizing/stretch/config and host of other SVG/React issues.

Create a generic Icon component,

const Icon = ({ name, children }) => (
    <svg className={`icon icon-${name}`}>
        {children}
    </svg>
)

Create the user Icon component,

const UserIcon = ({ fill }) => (
    // fill your inner svg code here, set fill to the correct react node
)

Upvotes: 0

Telion
Telion

Reputation: 777

This answered my question:

https://github.com/gilbarbara/react-inlinesvg

  1. Embed the CSS in the SVG document

    • Can't use your CSS preprocessors (LESS, SASS)
    • Can't target parent elements (button hover, etc.)
    • Makes maintenance difficult
  2. Link to a CSS file in your SVG document

    • Sharing styles with your HTML means duplicating paths across your project, making maintenance a pain
    • Not sharing styles with your HTML means extra HTTP requests (and likely duplicating paths between different SVGs)
    • Still can't target parent elements
    • Your SVG becomes coupled to your external stylesheet, complicating reuse.
  3. Embed the SVG in your HTML

    • Bloats your HTML
    • SVGs can't be cached by browsers between pages.
    • A maintenance nightmare

But there's an alternative that sidesteps these issues: load the SVG with an XHR request and then embed it in the document. That's what this component does.

I decided to use inline-svg for react, but I was also told about another method wrapping SVG into an object. I don't know anything about that as I haven't tried yet, but I'll list it just to fill up the collection:

<object>
  <embed src="/static/filename.svg">
</object>

Upvotes: 0

Related Questions