Reputation: 1364
I have some SVGs that have a defs
attribute with a style
tags inside.
Like this:
<svg ...>
<defs>
<style>.cls-1,.cls-7{fill:#b2488d;}.cls-1,.cls-2,.cls-3,.cls-4,.cls-5,.cls-6{stroke:#671f4d;}</style>
</defs>
...
</svg>
I want to use these SVGs in React, so I want to convert them to valid JSX. I already used tools like svg2jsx, but they strip the defs
tag away so none of the style attributes are present anymore. Is there a way to preserve the defs
with the style
tag inside by converting the SVG in JSX? Or is it not possible to use css classes in this case?
Upvotes: 22
Views: 13322
Reputation: 1092
You can preserve the styles without any conversion. For that wrap all the CSS classes inside the style tag with {` and `}. Now your SVG becomes like this
<svg ...>
<defs>
<style>{`.cls-1,.cls-7{fill:#b2488d;}.cls-1,.cls-2,.cls-3,.cls-4,.cls-5,.cls-6{stroke:#671f4d;}`}</style>
</defs>
...
</svg>
This will render without any problem.
Upvotes: 27
Reputation: 7575
If you created your SVG in Illustrater, save it with CSS Properties set to Presentation Attributes
. This way, you won't end up with a CSS classes and you are able to directly alter all attributes.
I exported an SVG that looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
<g>
<rect x="15.5" y="15.5" fill="#FFFFFF" width="44" height="44"/>
<path d="M59,16v43H16V16H59 M60,15H15v45h45V15L60,15z"/>
</g>
<g>
<path fill="#FFFFFF" d="M60.5,81.5c-12.1,0-22-9.9-22-22s9.9-22,22-22s22,9.9,22,22S72.6,81.5,60.5,81.5z"/>
<path d="M60.5,38C72.4,38,82,47.6,82,59.5S72.4,81,60.5,81S39,71.4,39,59.5S48.6,38,60.5,38 M60.5,37C48.1,37,38,47.1,38,59.5
S48.1,82,60.5,82S83,71.9,83,59.5S72.9,37,60.5,37L60.5,37z"/>
</g>
</svg>
I then got rid of all unneeded markup and just used it inside my component:
const Image = ( props ) => {
const {
hideSquare,
hideCircle,
} = props;
const colorSquare = props.colorSquare || '#fff';
const colorCircle = props.colorCircle || '#fff';
return (
<svg x="0px" y="0px" viewBox="0 0 100 100">
{ hideSquare ? null : (
<g>
<rect x="15.5" y="15.5" fill={ colorSquare } width="44" height="44"/>
<path d="M59,16v43H16V16H59 M60,15H15v45h45V15L60,15z"/>
</g>
) }
{ hideCircle ? null : (
<g>
<path fill={ colorCircle } d="M60.5,81.5c-12.1,0-22-9.9-22-22s9.9-22,22-22s22,9.9,22,22S72.6,81.5,60.5,81.5z"/>
<path d="M60.5,38C72.4,38,82,47.6,82,59.5S72.4,81,60.5,81S39,71.4,39,59.5S48.6,38,60.5,38 M60.5,37C48.1,37,38,47.1,38,59.5
S48.1,82,60.5,82S83,71.9,83,59.5S72.9,37,60.5,37L60.5,37z"/>
</g>
) }
</svg>
);
};
class Wrapper extends React.Component {
constructor( props ) {
super( props );
// Set default state
this.state = {
selectedColor: 'lightgreen',
hideSquare: false,
hideCircle: false,
};
}
// onInput callback
changeColor = ( e ) => {
this.setState( { selectedColor: e.target.value } );
}
changeVisibility = ( e ) => {
const { name, checked } = e.target;
this.setState( { [ name ]: checked } );
}
render() {
return (
<div>
<select onInput={ this.changeColor }>
<option>lightgreen</option>
<option>pink</option>
<option>red</option>
</select><br />
<label><input type="checkbox" name="hideSquare" onChange={ this.changeVisibility } /> hideSquare</label>
<label><input type="checkbox" name="hideCircle" onChange={ this.changeVisibility } /> hideCircle</label><br />
<Image
hideSquare={ this.state.hideSquare }
hideCircle={ this.state.hideCircle }
colorSquare={ this.state.selectedColor }
colorCircle={ this.state.selectedColor }
/>
</div>
);
}
}
ReactDOM.render( <Wrapper />, document.getElementById( 'app' ) );
svg {
width: 200px;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Upvotes: 11