I want to load an SVG from a file or through a URL and then use it as a React component.
I've tried many ways, but I can't figure out to do that correctly.
Can someone give me a hint to achieve it?
Currently I'm creating components this way, but as I mentioned, it should be at runtime loaded from a file instead:
const SvgComponent = (props) => (
<svg
height={800}
width={800}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
xmlSpace="preserve"
{...props}
>
<path
fill={props.color || '#000'}
d="M23 24H3v-2h18V6.4L16.6 2H5v7H3V0h14.4L23 5.6z"
/>
<path
fill={props.color || '#000'}
d="M22 8h-7V2h2v4h5zM4.8 15.4l-3-4.4h2.3L6 13.9 7.9 11h2.3l-3 4.4 3.1 4.6H8l-2-3.1L4 20H1.7l3.1-4.6z"
/>
</svg>
)
For a URL, you'd just use the image tag <img src={svgUrl} ...>
I suppose you could also fetch or read from file the SVG data as you would any other data and render it {svgData}.
You can use FileReader's readAsDataURL and set the result to an image's src, or read the file (or fetch the data) an use <img src={URL.createObjectURL(photoData)} alt={photoName} /> or similar.
Related
I have a Vue 2 project that uses v-calendar and I'd like to test it using #testing-library/vue.
The library encourages you to use getByRole and specify a name to narrow down the results but here I can't since the DOM comes from an external library.
I can't either use getByTestId for the same reason.
The content of the button is an SVG so getByText is not possible neither.
Is it ok in this specific case to use the container returned from the render method and do container.querySelector('vc-nav-arrow is-left')?
<div role="button" class="vc-arrow is-left">
<svg data-v-63f7b5ec="" width="26px" height="26px" viewBox="0 -1 16 34" class="vc-svg-icon"><path data-v-63f7b5ec="" d="M11.196 10c0 0.143-0.071 0.304-0.179 0.411l-7.018 7.018 7.018 7.018c0.107 0.107 0.179 0.268 0.179 0.411s-0.071 0.304-0.179 0.411l-0.893 0.893c-0.107 0.107-0.268 0.179-0.411 0.179s-0.304-0.071-0.411-0.179l-8.321-8.321c-0.107-0.107-0.179-0.268-0.179-0.411s0.071-0.304 0.179-0.411l8.321-8.321c0.107-0.107 0.268-0.179 0.411-0.179s0.304 0.071 0.411 0.179l0.893 0.893c0.107 0.107 0.179 0.25 0.179 0.411z"></path></svg>
</div>
I'm working on a small project with ASP.NET MVC and VueJs. I created some components and added them to the Project.js file like so:
<div class="card_four">
<a href="#Url.Action('LoanRequest', 'LoanOrigination')">APPLY NOW
<i class="icon">
<svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.584961 11.5841L5.17099 6.99807L0.584961 2.41205L1.99896 0.998047L7.99899 6.99807L1.99896 12.9981L0.584961 11.5841Z" fill="white"></path>
</svg>
</i>
</a>
<p>No collateral Needed</p>
</div>
When I clicked on the link, the asp.net MVC URL link broke. How can I rewrite this URL action in the vuejs compatible format as I'm new to VueJs
The # symbol is razor syntax. In js frameworks you no longer have the # symbol. In the case of urls, you usually just use strings. Just use
<a href='/loanorigination/loanrequest'>APPLY NOW
Or for more flexibility, look up Vue Properties and pass it in to your component as a property called something like loanUrl and use {loanUrl} in place of the string above.
I am building a React application that serves as a community directory for a global music scene I am a part of. I am trying to follow an SVG icon strategy that wraps the SVG code with a functional React component so that you can then import the icon into the component that uses it as a React component (NYT Article that outlines the strategy). This strategy is working for some components, but for many, I am getting parsing errors along the lines of:
./src/Components/LargeScopeComponents/ArtistProfileDisplay/TopBar/SVG/ListViewIcon/ListViewIconDarkTheme.js
Line 4: Parsing error: Unexpected token, expected "}"
2 |
3 | const ListViewIconDarkTheme = () => (
> 4 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 57.72 53.2"><defs><style>.cls-1{fill:#fff}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M15.38 41.72h42.35V53.2H15.38zM.41 41.72h10.86V53.2H.41zM15.15 20.86H57.5v11.48H15.15zM0 20.86h10.86v11.48H0zM15.15 0H57.5v11.48H15.15zM0 0h10.86v11.48H0z"/></g></g></svg>
| ^
5 | );
6 |
7 | export default ListViewIconDarkTheme;
I'm not completely sure why the javascript parser doesn't like the SVG syntax, because this strategy is working for other components. For example, I used the same strategy to create this functional component, and the javascript parser did not complain when I included it in a card component I use it in.
import React from 'react';
const CircleUpIcon_LightTheme = () => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 83.28 83.28"><g data-name="Layer 2"><g data-name="Layer 1"><circle cx="41.64" cy="41.64" r="38.64" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="6"/><path d="M41.64 20.7L20.92 56.58h41.43L41.64 20.7z"/></g></g></svg>
);
export default CircleUpIcon_LightTheme;
I'm wondering if there are any workarounds to this or modifications I could make to the SVG syntax to please the javascript parser. Any help would be much appreciated :)
The problem is that svg syntax clashes with jsx. React supports most svg element types (see: https://reactjs.org/docs/dom-elements.html#all-supported-svg-attributes), but for things like <style> you need to make the children react compatible. For example:
<style>{
`.cls-1{fill:#fff}`
}</style>
Notice the extra braces, and converting the child to a string. This should fix your first error.
The style tag in ListViewIconDarkTheme is causing the problem.
Why don't you try this? (see style attribute)
const ListViewIconDarkTheme = () => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 57.72 53.2"><g
id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path
class="cls-1" style="fill:#fff" d="M15.38 41.72h42.35V53.2H15.38zM.41
41.72h10.86V53.2H.41zM15.15 20.86H57.5v11.48H15.15zM0
20.86h10.86v11.48H0zM15.15 0H57.5v11.48H15.15zM0 0h10.86v11.48H0z"/></g></g> .
</svg>
);
export default ListViewIconDarkTheme;
My Question:
How do I fetch a .svg file and use it with <svg> tag, so I could also interactively style it (on hover for example), and not like I did in my example with <img> tag?
Goal:
Create a thumbnail view that shows the flag of each country (149 in number) on my main route '/'
Problem:
I've set a static route in my Express code, so all the flags to be available.
server.js:
app.use('/flags', express.static(FLAGS_FILES));
app.get('/flags', async (req, res) => {
let myFlags;
await readdir('data/flag-icons/')
.then((flags) => myFlags = flags)
.catch(err => console.log('Error:', err))
res.json(myFlags)
});
On the client-side, I want to fetch each .svg file and inline it into my Component.
My React Component look like this:
MapThumbnail Component:
render(){
const {flagcode} = this.props;
const filepath = `/flags/${mapcode}/vector.svg`;
console.log('filepath:', filepath);
return (
<MapThumbnailStyle>
<img src={filepath}
alt={flagcode}
title={flagcode}
width='40px'
height='40px'
/>
</MapThumbnailStyle>
);
}
https://github.com/gilbarbara/react-inlinesvg looks like it would help you.
You can in most of the cases directly inline the contents of the SVG file inside the render function, like -
TL;DR
react-svg-loader
It provides a webpack-loader, a CLI, and a few other tools that convert an SVG file to a React Component which contains the SVG file's contents inline in the render method.
The gist of the idea is the following -
vector.svg
<svg>
<circle cx="50" cy="50" r="25" stroke-width="5" />
</svg>
Vector.js
Now create a vector.js and just copy the contents of the SVG like below
import React from "react"
export default () => (
<svg>
<circle cx="50" cy="50" r="25" stroke-width="5" />
</svg>
);
and you can hand edit some elements here or assign ids to animate them.
MapThumbnail Component
And in your MapThumbnail component, you can import it as JS and style the SVG the way you want -
import Vector from "./path/to/vector";
// ...
// ...
render() {
return <div>
<Vector />
</div>
}
This conversion of SVG to a React Component can be automated to some levels and is provided by a few tools - one such tool is react-svg-loader. Disclaimer - I'm the author of react-svg-loader.
Best way is Lazy load the SVG component
const SvgComponent = React.lazy(() => import('../filepath.svg'))
return (
<React.Suspense fallback={<p>Loading...</P>}>
<SvgComponent />
</React.Suspense>
)
And this solution also works in React Native along with react-native-svg-transformer module.
Is it possible to embed SVG markup into a ReactJS component?
render: function() {
return (
<span>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmln ...
</span>
);
}
Results in the error:
Namespace attributes are not supported. ReactJSX is not XML.
What is the lightest way of doing this. Using something like React ART is way overkill for what I'm trying to do.
Update 2016-05-27
As of React v15, support for SVG in React is (close to?) 100% parity with current browser support for SVG (source). You just need to apply some syntax transformations to make it JSX compatible, like you already have to do for HTML (class → className, style="color: purple" → style={{color: 'purple'}}). For any namespaced (colon-separated) attribute, e.g. xlink:href, remove the : and capitalize the second part of the attribute, e.g. xlinkHref. Here’s an example of an svg with <defs>, <use>, and inline styles:
function SvgWithXlink (props) {
return (
<svg
width="100%"
height="100%"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<style>
{ `.classA { fill:${props.fill} }` }
</style>
<defs>
<g id="Port">
<circle style={{fill:'inherit'}} r="10"/>
</g>
</defs>
<text y="15">black</text>
<use x="70" y="10" xlinkHref="#Port" />
<text y="35">{ props.fill }</text>
<use x="70" y="30" xlinkHref="#Port" className="classA"/>
<text y="55">blue</text>
<use x="0" y="50" xlinkHref="#Port" style={{fill:'blue'}}/>
</svg>
);
}
Working codepen demo
For more details on specific support, check the docs’ list of supported SVG attributes. And here’s the (now closed) GitHub issue that tracked support for namespaced SVG attributes.
Previous answer
You can do a simple SVG embed without having to use dangerouslySetInnerHTML by just stripping the namespace attributes. For example, this works:
render: function() {
return (
<svg viewBox="0 0 120 120">
<circle cx="60" cy="60" r="50"/>
</svg>
);
}
At which point you can think about adding props like fill, or whatever else might be useful to configure.
If you just have a static svg string you want to include, you can use dangerouslySetInnerHTML:
render: function() {
return <span dangerouslySetInnerHTML={{__html: "<svg>...</svg>"}} />;
}
and React will include the markup directly without processing it at all.
According to a react developer, you dont need the namespace xmlns. If you need the attribute xlink:href you can use xlinkHref from react 0.14
Example
Icon = (props) => {
return <svg className="icon">
<use xlinkHref={ '#' + props.name }></use>
</svg>;
}
If you want to load it from a file, you may try to use React-inlinesvg - that's pretty simple and straight-forward.
import SVG from 'react-inlinesvg';
<SVG
src="/path/to/myfile.svg"
preloader={<Loader />}
onLoad={(src) => {
myOnLoadHandler(src);
}}
>
Here's some optional content for browsers that don't support XHR or inline
SVGs. You can use other React components here too. Here, I'll show you.
<img src="/path/to/myfile.png" />
</SVG>
You can import svg and it use it like a image
import chatSVG from '../assets/images/undraw_typing_jie3.svg'
And ise it in img tag
<img src={chatSVG} className='iconChat' alt="Icon chat"/>
The best way I found was this site
https://react-svgr.com/playground/
You copy an svg and it give you a react functional component with the svg transformed to react code.
There is a package that converts it for you and returns the svg as a string to implement into your reactJS file.
https://www.npmjs.com/package/convert-svg-react