@mapbox/svg-react-transformer
v2.1.0
Published
Transform SVG into JSX or React component modules
Downloads
131
Maintainers
Readme
@mapbox/svg-react-transformer
Transform SVGs into JSX or React component modules.
This module takes one string (the SVG) and converts it to another string (the JSX or React component module). That low-level focus means it can be used by a variety of higher-level modules that target specific contexts. Examples:
- svg-react-transformer-writer: A Node API and CLI for reading SVG files and writing React component module files.
- svg-react-transformer-loader: A Webpack loader for transforming SVG files into React component modules.
Installation
npm install @mapbox/svg-react-transformer
API
toComponentModule
svgReactTransformer.toComponentModule(svg, [options])
Returns a Promise that resolves with the React component module string.
Runs an SVG string through toJsx
to get a JSX string, then inserts the JSX into a templated React component module.
svg (toComponentModule)
Type: string
.
Required.
The input SVG.
options (toComponentModule)
options.svgoPlugins (toComponentModule)
Type: Array<Object>
.
See the same option for toInlineSvg
.
options.name (toComponentModule)
Type: string
.
Default: 'SvgComponent'
.
A name for the React component class.
The value will be converted to PascalCase (e.g. fancy-pants -> FancyPants
) and then passed as the id
option to toJsx
.
options.propTypes (toComponentModule)
Type: string
.
A stringified object defining propTypes
for the generated React component.
It should be the string of the code that you'd put in here: MyComponent.propTypes = ${this.place}
, e.g. '{ title: PropTypes.string.isRequired }'
.
This value will be passed to your selected template.
If this value is defined, the built-in templates will include const PropTypes = require('prop-types');
.
To programmatically convert a real object to a string that works here, I suggest using stringify-object.
options.defaultProps (toComponentModule)
Type: string
.
A stringified object defining defaultProps
for the generated React component.
It should be the string of the code that you'd put in here: MyComponent.defaultProps = ${this.place}
, e.g. '{ title: 'Untitled' }'
.
This value will be passed to your selected template.
To programmatically convert a real object to a string that works here, I suggest using stringify-object.
options.template (toComponentModule)
Type: Function | 'default' | 'fancy'
.
Default: 'default'
.
If the value is a string
, it can be one of the component module template values described below: default
, fancy
.
If the value is a function
, it must be a custom template function.
options.precompile (toComponentModule)
Type: boolean
.
Default: false
.
If true
, the template will be passed through Babel (with the ES2015 and React presets), so you don't have to compile it yourself.
Component module templates
default
template
The default template creates a module exporting a React.PureComponent
that renders the SVG element and its children as React elements.
This template is simple and unopinionated.
Here's an example generated by the default template.
"use strict";
const React = require("react");
class SvgComponent extends React.PureComponent {
render() {
return (
<svg {...this.props} viewBox="0 0 18 18">
<path d="M7 4l1.6 4H5.5S4.1 6 3 6h-.8L3 8l1 3h4.6L7 15h2l3.2-4H14c1 0 2-.7 2-1.5S15 8 14 8h-1.8L9 4H7z" />
</svg>
);
}
}
SvgComponent.defaultProps = {
role: "img",
focusable: "false"
};
module.exports = SvgComponent;
fancy
template
This is an opinionated template with a few nice features:
- Applies some accessibility patterns.
Adds
aria-hidden
andfocusable="false"
to the<svg>
element, and exposes analt
prop for alternative text (hidden from sight, legible for screen readers). - Uses the SVG's
viewbox
attribute to determine an aspect ratio, and applies a wrapper<div>
and CSS so that the element can have a fluid width while preserving its aspect ratio (across browsers IE11+). - Adds extra SVGO plugins
removeTitle
,removeStyleElement
, andremoveAttrs
to removewidth
andheight
from the<svg>
element. Thealt
prop provides better accessibility than titles for almost all use cases;<style>
elements within SVGs can be dangerous for inlined SVG; and width and height will be determined by the SVG's containing context. - Exposes
containerClassName
,containerStyle
,svgClassName
, andsvgStyle
props for customizing the whole thing.
Here is an example generated by the fancy template:
"use strict";
const React = require("react");
class Fakery extends React.PureComponent {
render() {
const containerStyle = this.props.containerStyle || {};
if (!containerStyle.position || containerStyle.position === "static") {
containerStyle.position = "relative";
}
containerStyle.paddingBottom = "100%";
const svgStyle = this.props.svgStyle || {};
svgStyle.position = "absolute";
svgStyle.overflow = "hidden";
svgStyle.top = 0;
svgStyle.left = 0;
svgStyle.width = "100%";
const text = !this.props.alt
? null
: <div style={{ position: "absolute", left: -9999 }}>
{this.props.alt}
</div>;
return (
<div style={containerStyle} className={this.props.containerClassName}>
<svg
aria-hidden={true}
focusable="false"
style={svgStyle}
className={this.props.svgClassName}
viewBox="0 0 18 18"
>
<g
style={{
marginTop: "0"
}}
>
<path d="M3.4 9.2c.1-1.1.4-2.3 1.5-3.2.9-.7 1.8-.8 2.9-.5 1.4.5 1 .5 2.4 0 1.5-.6 3 0 3.7.8.1.2.2.3 0 .4-1.8 1.3-1.6 3.9.3 5 .2.1.3.2.2.4-.4 1-1 1.9-1.7 2.7-.5.5-1.1.7-1.8.4-.1 0-.3-.1-.4-.1-.9-.1-1.7-.1-2.5.2-.3.1-.5.2-.8.3-.4.1-.8-.1-1.1-.4-.7-.5-1.1-1.2-1.5-1.9-.7-1.1-1.2-2.7-1.2-4.1" />
<path d="M11.6 2.5c0 1.2-1 2.4-2 2.7-.6.1-.8 0-.7-.6.2-1.2 1.2-2.2 2.5-2.5.2 0 .2 0 .2.2v.2" />
</g>
</svg>
{text}
</div>
);
}
}
module.exports = Fakery;
Custom template functions
Custom template functions receive one argument, a data object, and must return a string. The data object argument includes the following properties:
name
: The value of thename
option above (converted to PascalCase).propTypes
: The value of thepropTypes
option, above.defaultProps
: The value of thedefaultProps
option above.jsxSvg
: The JSX string generated from your source SVG.inlineSvg
: Your source SVG processed by SVGO for use inline with HTML. (In a template you could use this withdangerouslySetInnerHTML
.)
What about other modules that do similar things?
There are many npm packages for converting SVGs to React components: Webpack loaders, Browserify transforms, CLIs, Gulp plugins, Brunch plugins, etc. They are all addressing the same problem but formatting their output differently. However, their APIs seems to be too specialized for them to share logic, so they end up reimplementing a lot of the same stuff in different ways.
There are only a few steps to accomplish what we all want:
- Optimize the SVG with SVGO.
- Transform the SVG to JSX (or a React element object).
- Plug the JSX into a React component module.
Then you need an API that allows the user to configure these steps; that is, to specify SVGO plugins and control the React component output.
So that's the goal of this package: provide an API to accomplish those steps (without unnecessarily reimplementing functionality that (should) belong to other packages). Ideally, then, this package could be used by Webpack loaders, Browserify transforms, CLIs, Gulp plugins, Brunch plugins, etc., and save them from reimplementing the same functionality over and over again.
toJsx
svgReactTransformer.toJsx(svg, [options])
Returns a Promise that resolves with the JSX string.
Runs an SVG through toInlineSvg
, then converts the SVG to JSX.
svg (toJsx)
Type: string
.
Required.
The input SVG.
options (toJsx)
Any of the options for toInlineSvg
.
These are passed directly to that function.
toInlineSvg
svgReactTransformer.toInlineSvg(svg, [options])
Returns a Promise that resolves with your SVG processed by SVGO so that it works inline within HTML and is otherwise optimized.
You could use the result with dangerouslySetInnerHTML
, for example.
It's also used internally by toComponentModule
.
svg (toInlineSvg)
Type: string
.
Required.
The input SVG.
options (toInlineSvg)
options.svgoPlugins (toInlineSvg)
Type: Array<Object>
.
Configuration for SVGO plugins.
The following are automatically set (but can be overridden) because they are important for SVGs that will be inserted inline into an HTML document:
[
{ removeDoctype: true },
{ removeComments: true },
{ removeXMLNS: true },
{
// svgId is determined by the `id` option, below.
cleanupIDs: { prefix: svgId + '-' }
}
]
options.id (toInlineSvg)
Type: string
.
Default: a cuid
-generated string.
Used by SVGO's cleanupIDs
plugin to scope id
attributes.
Any characters other than /[a-zA-Z0-9]/
will be stripped.