/svg-to-react

Converts SVG assets into accessible React components with smart default props

Primary LanguageTypeScriptMIT LicenseMIT

@twilio-labs/svg-to-react

A utility to convert raw SVG files into accessible and extendable React Components. Why icon components?.

Code of Conduct PRs Welcome


Installation

# Yarn
yarn add @twilio-labs/svg-to-react --dev

# NPM
npm i @twilio-labs/svg-to-react --save-dev

Usage

CLI

Follow the on-screen instructions after running

yarn build
yarn convert

NodeJS

const fs = require('fs');
const {convertSvgToReact} = require('@twilio-labs/svg-to-react');

fs.readFile(`path/to/file`, 'utf8', async (err, fileContents) => {
    // TODO: Handle error case here

    // Convert the SVG into our ideal format
    // Arguments: SVG Contents, Options
    const generatedComponent = await convertSvgToReact(fileContents, {useHooks: false});

    fs.writeFile(`path/to/output/file`, generatedComponent, 'utf8', err => {
        // TODO: Handle error case here
    });
});

Options

option name type details
useHooks boolean Whether to use 'hooks', a feature only available in React 16.7+
template function Allows you to pass your own template function.

Dependencies

The generated React component depends on react-uid for accessibility by default. We recommend this library for unique ID generation to satisfy accessibility needs. You can avoid this dependency by providing a custom template.

Contributing

This project welcomes contributions from the community.

Code of Conduct

Please be aware that this project has a Code of Conduct. The tl;dr is to just be excellent to each other ❤️

Maintainers

This project is maintained by the design systems team.


Example

This project is used by Twilio's internal design system. Check it out to see how we use a custom template to make this even more powerful.

Demo

Input

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, 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 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
  .st0{fill:#001833;}
</style>
<path id="path-1_1_" class="st0" d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M12,20c-4.4,0-8-3.6-8-8
  s3.6-8,8-8s8,3.6,8,8S16.4,20,12,20z M14.3,15.3H16L12.9,8h-1.7L8,15.3h1.7l0.6-1.4h3.4L14.3,15.3z M10.8,12.6L12,9.7l1.2,2.8h-2.4
  V12.6L10.8,12.6z"/>
</svg>

Output (useHooks = false)

/**!
 * This file was automatically generated with @twilio-labs/svg-to-react
 */
import React from 'react';
import {UID} from 'react-uid';

export interface AutomaticIconProps {
  className?: string;
  size?: number;
  color?: string;
  title?: string;
  decorative?: boolean;
}

const AutomaticIcon = ({title = 'Automatic Icon', decorative = true, className, color, size}: AutomaticIconProps) => (
  <UID>
    {titleId => (
      <div style={{color, width: size, height: size}} className={className}>
        <svg 
          role="img"
          aria-hidden={decorative}
          height="100%"
          width="100%"
          viewBox="0 0 24 24"
          aria-labelledby={titleId}>
          {title ? <title id={titleId}>{title}</title> : null}
          <path
            fill="currentColor"
            d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm0 18c-4.4 0-8-3.6-8-8s3.6-8 8-8 8 3.6 8 8-3.6 8-8 8zm2.3-4.7H16L12.9 8h-1.7L8 15.3h1.7l.6-1.4h3.4l.6 1.4zm-3.5-2.7L12 9.7l1.2 2.8h-2.4v.1z"
          />
        </svg>
      </div>
    )}
  </UID>
);

export default AutomaticIcon;

Output (useHooks = true)

/**!
 * This file was automatically generated with @twilio-labs/svg-to-react
 */
import React from 'react';
import {useUID} from 'react-uid';

export interface AutomaticIconProps {
  className?: string;
  size?: number;
  color?: string;
  title?: string;
  decorative?: boolean;
}

const AutomaticIcon = React.memo(
  ({title = 'Automatic Icon', decorative = true, className, color, size}: AutomaticIconProps) => {
    const titleId = useUID();
    return (
      <div style={{color, width: size, height: size}} className={className}>
        <svg 
          role="img"
          aria-hidden={decorative}
          height="100%"
          width="100%"
          viewBox="0 0 24 24"
          aria-labelledby={titleId}>
          {title ? <title id={titleId}>{title}</title> : null}
          <path
            fill="currentColor"
            d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm0 18c-4.4 0-8-3.6-8-8s3.6-8 8-8 8 3.6 8 8-3.6 8-8 8zm2.3-4.7H16L12.9 8h-1.7L8 15.3h1.7l.6-1.4h3.4l.6 1.4zm-3.5-2.7L12 9.7l1.2 2.8h-2.4v.1z"
          />
        </svg>
      </div>
    );
  }
);

export default AutomaticIcon;