How to apply onClick event on Svg file on React? - reactjs

I made a component for a Svg and I'm trying to apply onClick event so I change the state, but it doesnt work for some reason, I'm not sure what I'm doing wrong. I tried applying the onCLick on too , but it doesnt work either.
my code
import React, { useState } from "react";
import './style.scss'
const AverageSvg=() => {
const [active, setActive] = useState(false);
return (
<svg className="average" onClick={() => setActive(false)}
xmlns="http://www.w3.org/2000/svg"
width="170.539"
height="51.974"
viewBox="0 0 170.539 51.974"
>
<g data-name="The average" transform="translate(-1223 -2501)" >
<g className={active ? "clicked-fill" : "fill "}
// fill="none"
stroke="#707070"
strokeWidth="1"
data-name="Rectangle 60"
transform="translate(1223 2501)"
>
<rect
width="170.539"
height="51.974"
stroke="none"
rx="25.987"
></rect>
<rect
width="169.539"
height="50.974"
x="0.5"
y="0.5"
rx="25.487"
></rect>
</g>
<text className="text"
// fill="#464646"
data-name="The average"
fontFamily="ArialMT, Arial"
fontSize="17"
transform="translate(1261 2532)"
>
<tspan x="0" y="0" >
The average
</tspan>
</text>
</g>
</svg>
);
}
export default AverageSvg;

Have you tried wrapping the svg with another tag like a div or span and attaching the onClick on that wrapper ?
Also inside the setActive() you should pass true instead of false.

you can warp the SVG in another tag as Alexader says, also you can pass the event to the child element in the SVG tag directly and it will work. but you should be aware of the browser compatibility
check this link from MDN web Docs
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/onclick
for example, this is an SVG delete icon
export const Delete = ({ ...props }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" className={props?.className} >
<path onClick={props?.onClick} d="M7 21q-.825 0-1.412-.587Q5 19.825 5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413Q17.825 21 17 21Zm2-4h2V8H9Zm4 0h2V8h-2Z" />
</svg>
)
}
when you call it just <Delete onClick={yourEvent} />
the onClick will apply on the <path/> tag

Related

How is SVG format images are set in React.Js?

I have been working on my college website and to make things easier and time saving, I downloaded a template and completed half of the requirements of my project but I got some issues while finding new image formats like svg as I didn't learn about handling them earlier.
Can anyone tell me how to use use svg format images because they are written in xml...!!
I surfed through many websites still can't get out my problem ,please help me out.
The easiest way to use SVG images in react is by importing them and using them in the <img /> src.
import myLogo from '/path/to/image.svg'
const Button = () => {
return (
<button>
<img src={myLogo} alt="SVG logo image"/>
</button>
);
}
Setting them as background images and such with CSS:
.container {
background-image: url(/path/to/image.svg);
}
Converting into JSX:
Regular SVG tag:
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
/>
</svg>
React:
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
/>
</svg>
SVG as a React Component
/path/to/LeftArrow.jsx
export const LeftArrow = () =>{
return(
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
/>
</svg>
)
};
import { LeftArrow } from './path/to/LeftArrow.jsx'
export const Button = () =>{
return(
<button>
<LeftArrow />
</button>
)
};
Use SVGR as data-url
This is what I do as it allows me to use SVGs as inline elements.
npm install svg-url-loader --save-dev
webpack.config.js
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
limit: 10240,
// make all svg images to work in IE
iesafe: true,
},
},
],
},
],
},
};
import myLogo from '/path/to/image.svg'
const Button = () => {
return (
<button>
<img src={myLogo} alt="SVG logo image"/>
</button>
);
};
This will compile it into a URL like:
<img src="wes49idjdur935jujd8907jdh.svg" alt="SVG logo image" />
Most of the time when using React, you're likely going to want to render SVGs conditionally. A common example would be the "hamburger" menu (which changes upon click). I went ahead and included an example of that:
Hamburger.jsx
import React from 'react';
export const Hamburger = () =>{
const [ isOpen, setisOpen ] = React.useState(false)
return(
<React.Fragment>
{ isOpen ? (
<button
onClick={()=>setisOpen(false)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
):( <button
onClick={()=>setisOpen(true)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>
)
}
</React.Fragment>
)
};
Additional CSS to make the SVG appear properly:
svg {
height: 40px;
width: 40px;
}
Actually is very easy. You can configure webpack (or the bundler you are using) to import svgs directly as react components. You can use an img tag and add the route to the svg, it should render it directly as an image. An also you can rely on a library . All in all, even though they are written in xml, you can think about svg as images

Why isn't fill working on my svg when using props?

I expect the svg to turn red but it isn't changing at all from the color #D8D8D8. I see the fill in the svg and if I turn this into a parameter I can use it then, but I'd rather just set the fill using React props so I can set a hover via my css:
The svg code (which I got my my Sketch export):
<svg width="57px" height="33px" viewBox="0 0 57 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Rectangle</title>
<g id="Design" stroke="none" stroke-width="1" fill-rule="evenodd">
<g id="Mobile-Copy-6" transform="translate(-196.000000, -69.000000)" fill="#D8D8D8">
<rect id="Rectangle" x="196" y="69" width="57" height="33"></rect>
</g>
</g>
</svg>
My react code:
import { ReactComponent as Logo } from "../../assets/rect.svg";
export const Example = () => {
return (
<div>
<Logo fill="#C94141" />
</div>
);
};
I used create-react-app with the typescript template and the Logo is identified as the type:
React.FunctionComponent<React.SVGProps<SVGSVGElement>
you need to create you Logo as a component with passing props to it which you want to keep dynamic. Try creating a component like:
export default ({ fill = '#D8D8D8' }) => (
<svg width="57px" height="33px" viewBox="0 0 57 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Rectangle</title>
<g id="Design" stroke="none" stroke-width="1" fill-rule="evenodd">
<g id="Mobile-Copy-6" transform="translate(-196.000000, -69.000000)" fill={fill}>
<rect id="Rectangle" x="196" y="69" width="57" height="33"></rect>
</g>
</g>
</svg>
);
and then use this component simply by
import Logo from "../../components/logo.js";
export const Example = () => {
return (
<div>
<Logo fill="#C94141" />
</div>
);
};

Error when using Custom Icon for Switch Component

When I try to use the custom icon prop I get this error:
index.js:1406 Warning: Failed prop type: Invalid prop icon supplied to ForwardRef(Switch), expected a ReactNode.
I have tried several things and I cannot make it work. Any ideas why it is not working?
<Switch
checked={formik.values.roleBasedAccess}
onChange={handleRoleBasedChange}
icon={HexagonSwitch}
value="roleBasedAccess"
/>
And the HexagonSwitch component:
import React from 'react';
const HexagonSwitch = () => {
return (
<svg width="24px" height="21px" viewBox="0 0 24 24">
<g id="Add-on/Guided-Workflow/Pieces/Status-Indicator/Complete" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon id="Polygon" fill="red" fill-rule="nonzero" points="12 3 20 7.5 20 16.5 12 21 4 16.5 4 7.5"></polygon>
</g>
</svg>
);
};
The "Failed prop type" message is telling you that it expects a node, but you are providing a component type.
Component Type: HexagonSwitch
Node (i.e. instance of the component type): <HexagonSwitch/>
Below is a working example.
import React from "react";
import Switch from "#material-ui/core/Switch";
const HexagonSwitch = () => {
return (
<svg width="24px" height="21px" viewBox="0 0 24 24">
<g
id="Add-on/Guided-Workflow/Pieces/Status-Indicator/Complete"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<polygon
id="Polygon"
fill="red"
fillRule="nonzero"
points="12 3 20 7.5 20 16.5 12 21 4 16.5 4 7.5"
/>
</g>
</svg>
);
};
export default function Switches() {
const [checked, setChecked] = React.useState(true);
return (
<div>
<Switch
checked={checked}
onChange={event => setChecked(event.target.checked)}
value="checkedA"
icon={<HexagonSwitch />}
checkedIcon={<HexagonSwitch />}
inputProps={{ "aria-label": "secondary checkbox" }}
/>
</div>
);
}

React "base class"/ inheritance

I'm pretty new to React,
And I was given a simple home assignment.
I was asked to create 3 kinds of a clickable circle component.
The JSX is common to all (SVG),
But their
size
background color
onClick callback
are different.
What is the correct way nowadays (2019, React 16) to get such a common base class/
interface in React ?
HOC ? React Hooks ? some other way ?
Say this is my "base" Circle component
(Please ignore the hard coded props):
export default function Circle(props) {
return (
<svg height="100" width="100">
<circle cx="50" cy="50" r="26" fill="#9cc6d4" />
<circle
cx="50"
cy="50"
r="20"
stroke="#FFF"
strokeWidth="1"
fill="none"
/>
</svg>
);
I want to make myself clear:
I've only 3 different types of that basic Circle
(Say Red, Blue and Yellow...)
And I need to put them on screen according
to a JSON.
I don't want to DRY and create
3 different classes: RedCircle, BlueCircle and YellowCircle...
which eventually will be based on the same JSX
Your help is highly appreciated.
You can easily do these cutomizations with props..
const {size, onClick, bgColor} = props;
// now use the size, onClick and bgColor props in your JSX markup
return (
<svg height="100" width="100">
<circle cx="50" cy="50" r="26" fill="#9cc6d4" />
<circle
cx="50"
cy="50"
r="20"
stroke="#FFF"
strokeWidth="1"
fill="none"
/>
</svg>
);
Using the Circle component would look like
<Circle size={'40'} onClick={()=>{ console.log('im red circle'}) bgColor={'red'} />
<Circle size={'35'} onClick={()=>{ console.log('im green circle'}) bgColor={'green'} />
You can pass these infos, by using the props parameter of the function component.
Your component would look something like that:
export default function Circle(props) {
return (
<svg height={props.size} width={props.size}>
<circle cx="50" cy="50" r="26" fill={props.color} />
<circle
cx="50"
cy="50"
r="20"
stroke="#FFF"
strokeWidth="1"
fill="none"
/>
</svg>
);
}
Then, when used in parent components:
<Circle size={yourSize} color={yourColor}/>
In this case, size etc... would be available in the function as props.size etc...
You can do the same and pass event handlers like onClick etc...
Reference:
https://reactjs.org/docs/components-and-props.html

How to use a custom SVG file in material ui SVG ICON

I am trying to use a chip with SVG delete icon,
The icon code is
const icon = (props) => {
return (
<SvgIcon>
<img src={'ic_check.svg'} style={{width: '20px'}} width={'20px'}/>
</SvgIcon>
)
};
The content of SVG file
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fill-rule="evenodd">
<rect width="20" height="20" x="2" y="2" fill="#6FB934" rx="10"/>
<path fill="#FFF" fill-rule="nonzero" d="M9.5 15.475L6.025 12l-1.183 1.175L9.5 17.833l10-10-1.175-1.175z"/>
<path d="M0 0h24v24H0z"/>
</g>
</svg>
and the chip finally is
<Chip
label={ViewUtils.NOT_EXPIRED}
className={classes.chip}
onDelete={() => {}}
deleteIcon={<icon/>}/>
But this is not working and I checked for the path and it is correct as I can render same svg in img tag.
Nayan SvgIcon takes a svg path that you can further style. But in your case your svg is already styled. It doesn't take svg file directory path which actually lose SvgIcon API purpose.
You just need to remove SvgIcon from img tag:
<Chip
label={ViewUtils.NOT_EXPIRED}
className={classes.chip}
onDelete={() => {console.log('You Deleted this icon')}}
deleteIcon={icon}
/>
and Make you svg as const or import from assets file directory I haven't tried that,
const icon = <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fill-rule="evenodd">
<rect width="20" height="20" x="2" y="2" fill="#6FB934" rx="10"/>
<path fill="#FFF" fill-rule="nonzero" d="M9.5 15.475L6.025 12l-1.183 1.175L9.5 17.833l10-10-1.175-1.175z"/>
<path d="M0 0h24v24H0z"/>
</g>
</svg>
There is a reason why we can't make <icon/> component. If we make it as component as following:
const Icon = (props) => {
return (
<SvgIcon>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<g fill="none" fill-rule="evenodd">
<rect width="20" height="20" x="2" y="2" fill="#6FB934" rx="10" />
<path
fill="#FFF"
fill-rule="nonzero"
d="M9.5 15.475L6.025 12l-1.183 1.175L9.5 17.833l10-10-1.175-1.175z"
/>
<path d="M0 0h24v24H0z" />
</g>
</svg>
</SvgIcon>
)
};
It works like a charm but onDelete doesn't get fired on this component.I've reported this issue as well on material UI. In first case onDelete gets called every time. Feel free to ask any question.
EDITED Fixed the above issue for Icon as Component rather than const. here is the codesandbox link for working example:
https://codesandbox.io/s/98842r4yy4
I am using React and typescript, created a component and added the tags from HTML and it worked normally.
export const IconTable: React.FC = () => {
return (
<svg width="130" height="130" viewBox="0 0 1024 1024">
<path d="M505.947 123.597a23.096 23.096 0 0 0-16.99-7.477h-6.837c-17.929 0-32.631 13.468-34.198 "/>
</svg>
);

Resources