Hi guys,
Since long I wanted to work on and create package in React. I am mostly working in VueJS, thus this was a bit new experience for me.
Recently, we launched Unicons - an icon library containing 1000+ vector icons in unique line style as open source. And since then I wished to have package for React. Last Sunday, I was kinda free & thought to give it a try! And here I am writing this article.
How to
There were few ideas in my mind related to how I want to make it available. Some of them contains:
- Easy to use for everyone.
- Component based
- One should be able to load only icons that they need, keeping bundle size as low as possible.
I wrote a script that converts the SVGs to React components. I used folder based approach like lodash
to keep the bundle size smaller. Every component gets compiled into different React component file and gets imported to common index.js
for those who want to use all the icons.
Here is a sample component of comment
icon:
import React from 'react';
import PropTypes from 'prop-types';
const UilComment = (props) => {
const { color, size, ...otherProps } = props
return React.createElement('svg', {
xmlns: 'http://www.w3.org/2000/svg',
width: size,
height: size,
viewBox: '0 0 24 24',
fill: color,
...otherProps
}, React.createElement('path', {
d: 'M12,2A10,10,0,0,0,2,12a9.89,9.89,0,0,0,2.26,6.33l-2,2a1,1,0,0,0-.21,1.09A1,1,0,0,0,3,22h9A10,10,0,0,0,12,2Zm0,18H5.41l.93-.93a1,1,0,0,0,0-1.41A8,8,0,1,1,12,20Z'
}));
};
UilComment.propTypes = {
color: PropTypes.string,
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
UilComment.defaultProps = {
color: 'currentColor',
size: '24',
};
export default UilComment;
The build script that I wrote looks something like this:
const path = require('path')
const fs = require('fs-plus')
const cheerio = require('cheerio')
const upperCamelCase = require('uppercamelcase')
const iconsComponentPath = path.join(process.cwd(), 'icons')
const iconsIndexPath = path.join(process.cwd(), 'index.js')
const uniconsConfig = require('@iconscout/unicons/icons.json')
// Clear Directories
fs.removeSync(iconsComponentPath)
fs.mkdirSync(iconsComponentPath)
const indexJs = []
uniconsConfig.forEach(icon => {
const baseName = `uil-${icon.name}`
const location = path.join(iconsComponentPath, `${baseName}.js`)
const name = upperCamelCase(baseName)
const svgFile = fs.readFileSync(path.resolve('node_modules/@iconscout/unicons', icon.svg), 'utf-8')
let data = svgFile.replace(/<svg[^>]+>/gi, '').replace(/<\/svg>/gi, '')
// Get Path Content from SVG
const $ = cheerio.load(data, {
xmlMode: true
})
const svgPath = $('path').attr('d')
const template = `import React from 'react';
import PropTypes from 'prop-types';
const ${name} = (props) => {
const { color, size, ...otherProps } = props
return React.createElement('svg', {
xmlns: 'http://www.w3.org/2000/svg',
width: size,
height: size,
viewBox: '0 0 24 24',
fill: color,
...otherProps
}, React.createElement('path', {
d: '${svgPath}'
}));
};
${name}.propTypes = {
color: PropTypes.string,
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
${name}.defaultProps = {
color: 'currentColor',
size: '24',
};
export default ${name};`
fs.writeFileSync(location, template, 'utf-8')
// Add it to index.js
indexJs.push(`export { default as ${name} } from './icons/${baseName}'`)
})
fs.writeFileSync(iconsIndexPath, indexJs.join('\n'), 'utf-8')
console.log(`Generated ${uniconsConfig.length} icon components.`)
Earlier I tried to use webpack
and it didn't work out properly as it compiled them into single index.js
file.
Publishing it as npm package
I learned how to publish it as a npm package so that everyone can use it via simple npm install
. I've published it at https://www.npmjs.com/package/@iconscout/react-unicons
Use
You can use these icon by simple installing
npm i -s @iconscout/react-unicons
and then import individual icons in your component.
import React from 'react';
import UilReact from '@iconscout/react-unicons/icons/uil-react'
const App = () => {
return <UilReact size="140" color="#61DAFB" />
};
export default App;
I have also added props to customise color and size.
I would love to have suggestions from DEV.to community on how I can improve it. :)
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.