-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider importing SVGs as React components #1388
Comments
So, for example, on the starting page, instead of
it would be
Isn't that a little opinionated? |
This video convinced me that the way we should be using SVG is inline. This table, showing the features and benefits of implementing SVG using the three available techniques, cinched it for me: An SVG is different from all other assets (image, sound, video, etc) in that isn't a binary blob, and so can be more easily manipulated in our app. An SVG has more in common with a stateless react component than a JPEG. You can still do this:
Then again, I suppose I haven't thought through the scenario of using an SVG asset in CSS… |
I've ran into a similar problem/issue, I'd like to be able to reference SVGs and then adjust their |
as a workaround you can do something like: import React from 'react';
export default () =>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M2.001 9.352c0 1.873.849 2.943 1.683 3.943.031"/>
</svg> then you can take in props and use those to adjust the fill |
@kauffecup I'm new to ES6, React and this library so apologies if silly questions... Are you saying make a file called Also, thank you. |
@kauffecup I tried your method of inlining an SVG into a component, but am seeing a webpack hot dev client error that it cannot build the module... Any ideas what might be causing this? |
Update for anybody else seeing this: the issue was resolved when I removed namespaces from the svg, since |
@kauffecup that's adding extra js cruft to what should be a standalone svg resource. Not ideal. @edhenderson I think using svg-react-loader that I mention in the OP will get you what you want. It's working perfectly for me, of course you have to eject from create-react-app first. |
I appreciate the suggestion but I know some people are already using SVGs as sprites so I wouldn't like to break them. Especially given that it is easy to declare SVG inside a React component anyway. |
We have some options: 1Assume we have export default "components/Pin.hash.svg"
export function Pin(props) {
return (
<svg ...>...</svg>
)
} This way it will backward compatible with current CRA convention about SVGs. Advantage of using SVGs directly (instead of copy-pasting it to React component) is that you can edit it in visual editor, like Inkscape. 2Create CLI tool which will generate (and save to the disk) React Components from SVG files. It additionally can use svgmin. Developer can edit generated files afterwords or regenerate components whenever SVG changes. |
I feel like this issue has been closed prematurely. The main motivation seems to be BC (which is understandable) but the following statement is not necessarily true:
While it is easy to declare SVG in React code, that means it's all the more complicated to work with actual SVG files if you want them inline (as is the current recommendation). You basically need to manually create one component per icon and paste the SVG contents in them (and god knows some app can have a lot of icons), accounting for attributes changes (class => className) and such. My point is, considering the current recommendation seems to be to use inline SVGs it seems counterproductive for the default behavior of CRA to be using |
Agree with @Anahkiasen , I found this looking for a solution to using inline SVGs without ejecting and modifying the Webpack loader, and was disappointed to find that loading them as images was the expected behavior. I understand the reasoning, but the future-proof path and what I've done on every other project is Graphics Program => SVGO => Webpack loader => inline in document. |
Thanks for chiming in and keeping this discussion going. The fact that new people keep finding their way to this thread means more and more people expect CRA to allow them to:
Handling svgs as their own media type with their own loader allows for all of this. I hope we can re-open this issue one day. |
I realized that my first comment is not clear on what I'm proposing. My solution (1) is backward compatible with existing convention. import Pin from 'Pin.svg'; // you get svg url or base64 encoded data url
// which is the same as
import { default as Pin } from 'Pin.svg';
// but if you do this
import { Pin } from 'Pin.svg'; // you get React component with inline svg |
I achieved this using https://github.com/jhamlet/svg-react-loader explicitly on the one SVG I wanted to inline. import Logo from '-!svg-react-loader!./logo.svg'; The |
@gwagener I'm getting module resolve issues when using |
@kaumac Hm, I'm actually using create-react-app-ts so I had to add a declare module '*.svg' {
const content: string;
export default content;
} For the type definitions of SVG. Without that I also got module resolve issues. Also, I'm still getting module resolve issues testing with Jest. |
Hm, have tested in vanilla CRA instead of TypeScript and see that my suggestion won't work because Webpack loader syntax isn't allowed. ⏏ |
This worked for me after installing // Icon.js
const Icon = ({ icon, ...props }) => {
const svg = require(`!raw-loader!./icons/${icon}.svg`);
return <span {...props} dangerouslySetInnerHTML={{__html: svg}}/>;
}; Then I just use something like |
Please note that using Webpack loaders like this in a Create React App project is not supported and can break in any patch release. If you want to use Webpack loaders directly please eject (unless you’re okay with potential breakage in the future). |
Regarding proposal in #1388 (comment), it’s a bit counter intuitive to me. People are already confused by naming vs default exports, and I think repurposing it for an escape hatch doesn’t help. |
Let’s reopen as this seems popular. It’s not clear to me yet how to approach it in a way that wouldn’t break existing use cases. |
@gaearon does not break existing case import Pin from 'Pin.svg'; // you get svg url or base64 encoded data url
// which is the same as
import { default as Pin } from 'Pin.svg';
// but if you do this
import { Pin } from 'Pin.svg'; // you get React component with inline svg |
Yes, but as I mentioned in #1388 (comment), it’s pretty confusing. Maybe that’s okay for an escape hatch. If you send a PR for this, I can take a good look and make a more informed decision. |
I should point out that any of the above proposed workarounds that use custom loader syntax no longer work due to #803. |
@gaearon It's not a scape hatch, it's a discriminator on when to use the svg React component or when not to. I can't see a more elegant way for it. True that can be misleading, but documentation could minimize it. |
As an alternative to the default vs named import, how about updating the CRA webpack config to exclude a given extension (.inline.svg?) from url-loader/file-loader; and handling that extension with eg.
|
Please participate in a wider discussion about this approach: #3722. |
use: xlink:href => xlinkHref problem is == > Syntax error: Namespace tags are not supported. ReactJSX is not XML. |
This is now implemented in #3718. |
Support for this has been released in the first v2 alpha version. See #3815 for more details! |
This might not make it after all 😞 #3856 |
* Import SVGs as React components (facebook#1388) * Updated webpack production config and fixed tests * Improved Jest SVG file transform * Improved SVG tests * Add a comment * Update webpack.config.prod.js
* Import SVGs as React components (#1388) * Updated webpack production config and fixed tests * Improved Jest SVG file transform * Improved SVG tests * Add a comment * Update webpack.config.prod.js # Conflicts: # packages/react-scripts/package.json
I'm sorry to add noise, but what is considered the current stable best practice for inline SVGs? I got my SVGs from a designer (over 100 of them) and would not like to convert them to JSX. My react-scripts is at version 1.0.17 and I have no problem updating to a more recent stable version if it will make the difference. |
@neoziro I don't love it, but it'll work for me. Thanks! |
* Import SVGs as React components (facebook#1388) * Updated webpack production config and fixed tests * Improved Jest SVG file transform * Improved SVG tests * Add a comment * Update webpack.config.prod.js
I've gone with this approach, keeping my svgs in one file and importing them where needed, for example:
It's then imported as a complete standalone svg with full control. |
This was released in 2.0 stable. Workarounds are no longer needed. |
There is some bug or limitation you have to keep in mind when you have multiple svg's on one page. You need to check for unique id's in svg file path's and mask's as second, third svg will grab first match id from page. So you can find all svg's to be the same as first in the document. |
Probably my answer will be helpful anybody Add {
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/],
loader: require.resolve("url-loader"),
options: {
limit: 10000,
name: "static/media/[name].[hash:8].[ext]"
}
} Import import * as React from "react";
import { Icon } from "components";
import * as downArrow from "common/assets/down-arrow.svg";
const CollapseIcon = ({ condition }) => (
<Icon asset={downArrow} />
);
export default CollapseIcon; Current props can use in const Icon = styled.img.attrs<IconProps>({
src: ({ asset }: IconProps) => asset,
alt: ({ alt }: IconProps) => alt
})`
vertical-align: middle;
` |
@ravecat you can just use: import { ReactComponent as WhateverNameYouWant } from 'common/assets/down-arrow.svg'; and you get a nice inlined SVG. |
How about having svg components pure/memoized by default? At the moment to achieve the same I would have to do something like this
wouldn't it be better if this was done by default? |
@khaledosman Please create a new issue. |
It seems that
produces
|
@AlpacaGoesCrazy don't think you can do that, it's not a real import. It's using a Webpack plugin to transform the statement. You'll have to |
@philraj thank you, just did that and it works
however it would be nice to use direct exports for svg |
This has been fixed but hasn't been released yet: #5573 |
My own path of using SVGs with webpack has settled me comfortably with loading .svg files as react components via https://github.com/jhamlet/svg-react-loader (svg-react-loader@next as of time of writing). This allows you to treat an SVG just like any other React component, and renders out inline SVGs. For example:
Inline SVGs offer the most amount of flexibility in terms of styling, animation, and manipulating props. SVGs in the browser are now more supported than ever. They are quickly replacing icon fonts as the preferred way to do icons in your app.
I'd enjoy hearing the community's thoughts on this.
The text was updated successfully, but these errors were encountered: