Are you sick of the icons you have been using in your projects lately? Do you lack the artistic ability to draw a stick figure? If you answered yes (or no), please continue reading.
Since I began building things with JavaScript I have been using essentially the same icon set over and over. I often work with React and Styled Components so my go-to icon library has been Styled Icons. Styled Icons contains the same familiar icon sets we have probably all used at some point: Font Awesome, Material Design, Boxicons, etc. Even though there are thousands of choices and all of these icon collections are great in their own right, I got to the point where I couldn't find the right icons for my use cases and all my projects sort of looked the same. I thought creating my own icon set was way out of reach due to my complete lack of artistic talent. Turns out I was wrong.
Example Boxicons Chromium icon
The solution to my problem was Scalable Vector Graphics, or SVG. To get started you will need some kind of SVG editor. Here is a list of 7 free SVG editors. My personal preference is Boxy SVG, but I haven't tried any others 🙄. The great part about SVGs is that mathematical skills are more important than artistic skills. Boxy SVG has a ton of settings/options and taking the time to familiarize yourself with them is worthwhile. Here are the steps I take to create my icons with a few tips based on my experience.
Step 1 - Draw an icon
- Change the dimensions of the canvas to 50px by 50px
- Geometry options help size and position elements
- Backgrounds will be transparent unless you set the fill attribute
I used the Circle and the Pie tool to create this:
-
Hints
- Make one 120 degree pie piece
- Copy and Paste it two times
- Rotate the pieces to fit
- Put a circle on top of that
- The inner circle has a 1px white stroke
- Match colors with a Color Dropper Tool
Step 2 - Optimize your SVG
- Save your icon as an
svg
file - Go to OMGSVG and open your file. This web app is a cool utility that simplifies the markup required to render your svg.
- Change settings and toggle the Show Original button to see the difference
- Image / Markup tabs while both change based on settings
- I generally use defaults and with Prettify Markup but customize when needed
The more complex your SVG the more dramatic the optimization:
An SVG looks great no matter what the size
Out final markup looks like this:
- Drop all the
xmln
stuff since we are using these with inline HTML - Add a
width
attribute to the SVG or use CSS to style
// Cleaned up SVG markup
<svg width='200' viewBox='0 0 50 50'>
<path
d='M15.362 4.281a23 23 0 0 1 32.478 23.07l-22.898-2.16z'
fill='#e94435'
/>
<path
d='M47.882 27.292a23 23 0 0 1-36.496 15.97l13.638-18.52z'
fill='#35a755'
/>
<path
d='M11.569 43.37a23 23 0 0 1 4.762-39.552l9.037 21.15z'
fill='#fabd05'
/>
<circle cx='25' cy='25' r='8' stroke='#fff' fill='#3f84f3' />
</svg>
Step 3 - Create a Reusable React Component
Svg
component will takename
as props- The
name
prop will tellSvg
what markup to return - Use
React.Fragment
shorthand<></>
to return output
import React from 'react'
// Pass any additional props via destructuring ...rest
function Svg({ name, ...rest }) {
// Helper function to return inner svg elements
// Each icon has its own case
// Throws error if no name prop is present
const getPath = n => {
switch (n) {
case 'google':
return (
<>
<path
d='M15.362 4.281a23 23 0 0 1 32.478 23.07l-22.898-2.16z'
fill='#e94435'
/>
<path
d='M47.882 27.292a23 23 0 0 1-36.496 15.97l13.638-18.52z'
fill='#35a755'
/>
<path
d='M11.569 43.37a23 23 0 0 1 4.762-39.552l9.037 21.15z'
fill='#fabd05'
/>
<circle cx='25' cy='25' r='8' stroke='#fff' fill='#3f84f3' />
</>
)
default:
throw Error('name is required!')
}
}
return (
<svg viewBox='0 0 50 50' {...rest}>
{getPath(name)}
</svg>
)
}
export default Svg
- Add as many icons as you need
- Use like any other React component
Step 4 - Other Ideas
- Set size via passing a
width
/height
prop or via CSS or however you style things - Pass
fill
orstroke
as a prop to change up colors
Now we have the Chromium icon ✨:
- To simplify the concept lets add a
dot
icon
If our new component looked like this:
function Svg({ name, fill = 'black' }) {
const getPath = n => {
switch (n) {
case 'dot':
return (
<>
<circle cx='25' cy='25' r='8' fill={fill} />
</>
)
case 'google':
return (
<>
<path
d='M15.362 4.281a23 23 0 0 1 32.478 23.07l-22.898-2.16z'
fill='#e94435'
/>
<path
d='M47.882 27.292a23 23 0 0 1-36.496 15.97l13.638-18.52z'
fill='#35a755'
/>
<path
d='M11.569 43.37a23 23 0 0 1 4.762-39.552l9.037 21.15z'
fill='#fabd05'
/>
<circle cx='25' cy='25' r='8' stroke='#fff' fill='#3f84f3' />
</>
)
default:
throw Error('name is required!')
}
}
return <svg viewBox='0 0 50 50'>{getPath(name)}</svg>
}
We could have React code like this:
<>
<Svg name='dot' />
<Svg name='dot' fill='rebeccapurple' />
<Svg name='dot' fill='orangered' />
<Svg name='dot' fill='greenyellow' />
</>
And render:
In Closing
Now you know how to make your own icons and turn them into an easy-to-use React component. Hopefully, you agree with my premise that minimal artistic ability is required. I would argue the most important skill is understanding the features of your preferred SVG editor. There is a time investment here but I use working on these icons as a break from the more mind crunching code of my main projects. I think the result is websites and applications that look better and are more engaging for the user.