As I am new to React (I come from Angular), I am not sure if there is a "React" way of doing this, but I am importing a json file, which has a property called content
which contains an svg string, it looks similar to this:
{
"content": "<svg width="24">...</svg>"
}
I then have a function to render the content of that json:
export interface IIconsObject { content: string; }
export interface IIconsProps extends ComponentPropsWithoutRef<'div'> {
icon: IIconsObject;
size?: 'small' | 'medium';
color?: string | 'default' | 'class';
}
export const Icon = (data: IIconsProps) => {
let content = data.icon.content;
const size = data.size === 'small' ? 16 : 24;
content = content.replace(/height="24"/g, `height="${size}"`);
content = content.replace(/width="24"/g, `width="${size}"`);
return <span dangerouslySetInnerHTML={{ __html: content }} />;
};
Right now I am doing regex to replace the width/height, but is there a better way to do this, such as using a dom selector that selects the svg
and then maybe using setAttribute like svg.setAttribute('width', size)
?
3
Answers
This is fine with
dangerouslySetInnerHTML
. I think you should keep it this way if you need to usedangerouslySetInnerHTML
.More React way:
useRef for access to
span
html node.spanRef.current
will contain regular DOM element.useEffect to make modification after
content
orsize
changes and react renders updated nodes.Note that you might need to remove
[content, size]
if your component gets rerendered without changes to those values becausedangerouslySetInnerHTML
will overwrite previous modifications.Yes, in React, there are more robust ways to handle SVG manipulation than using regex replacements on strings. Instead of manipulating the SVG string directly, you can convert the SVG string into a React component. This approach provides greater flexibility, allowing you to utilize React’s capabilities to manage attributes and state.
Here’s a step-by-step approach to refactor your current method:
Step 1: Convert SVG String to React Component
Instead of importing SVG as a string, consider using it directly as a React component. This can be achieved using libraries like @svgr/webpack, which can be set up in your project’s webpack configuration to import SVG files as React components.
If you prefer to continue using SVG as a string within your JSON (as your current project setup might require it), you can parse the SVG string to a React element using dangerouslySetInnerHTML as you did, or use a utility function to convert it into a React component dynamically.
Step 2: Dynamically Adjust SVG Properties
Once you have the SVG loaded as a React component, you can easily modify its properties such as width and height. Here’s how you can refactor your component:
useMemo caches the result for given
data.icon.content
andsize
.Might be late to the party but I’m here to suggest an approach using a library. At the end it would be very similar to @myrrtle’s answer but the benefit is that here you wouldn’t have to implement the DOM parsing logic yourself.
You could use html-react-parser which helps, as the name suggests, parsing HTML strings to React components. I prefer something like this because you have even more control with the parsing where implementing something like sanitizing the parsed HTML with isomorphic-dompurify or others becomes even easier.
In any case, something like this could do the trick:
You can check the following CodeSandbox for a demo on how to use this: