A simple way to add icons to an Astro site and to stay organized in the process.
We're going to create a simple system to make it easy for you to add icons to your Astro site. I like this approach because it can grow with the site. It works for a few icons (as we'll see), but scales easily.
Let's explore a bit of background first. Skip down to the next section if you want to dive right into the code.
I really like to use SVG icons because they scale to any size and change color without generating needing additional assets.
When generating these icons, I ensure each is a consistent size, has fill
attributes set to currentColor
, and have all strokes outlined. Read more about my icon process.
To make icons easier to manage, I generally like to have them in separate files. On smaller projects, I may start with them all in a single component, but typically break them out on more sizable projects.
In this case, we're going to start with individual icon files because it should cover your case, regardless of scale.
Let's get into the code!
Find a good location to put all your SVG icons. In the example project below, I've put these in src/components/Icon
. This way they are colocated with the icon component and easy to find in the project.
Here's what I do when adding new icons:
src/components/Icon
directory. Use .astro
as the file extension.fill
attributes to currentColor
.Here's an example of an icon called arrow-left
:
src/components/Icon/ArrowLeft.astro
<svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M15.5921 54.4923L43.0203 85.6988C44.8161 87.7689 44.4898 90.7935 42.5303 92.3857C41.5509 93.1818 40.4076 93.5 39.2651 93.5C37.9587 93.5 36.4899 92.863 35.5097 91.9078L1.22447 52.8997C-0.408162 51.1484 -0.408162 48.4413 1.22447 46.6901L35.5097 7.68191C37.3055 5.61182 40.4076 5.45274 42.3665 7.20404C44.4892 8.9553 44.6523 11.9806 42.8565 13.8909L15.5929 44.9395H95.1021C97.8773 44.9395 100 47.0096 100 49.716C100 52.4225 97.8773 54.4925 95.1021 54.4925L15.5921 54.4923Z"
fill="currentColor"></path>
</svg>
Here's the basic structure of the icon component with a few icons.
---
import ArrowLeft from './Icon/ArrowLeft.astro'
import Calendar from './Icon/Calendar.astro'
import Eye from './Icon/Eye.astro'
export interface Props {
name: 'arrow-left' | 'calendar' | 'eye'
}
const { name } = Astro.props
const iconMap: { [K in Exclude<Props['name'], undefined | null>]: string } = {
'arrow-left': ArrowLeft,
calendar: Calendar,
eye: Eye,
}
const IconComponent = iconMap[name]
---
<IconComponent />
To render an icon, you would import the component and then use the name
property to specify the component you want to render.
---
import Icon from '@components/Icon.astro'
---
<Icon name="arrow-left" />
You can certainly omit the TypeScript here. However, as TS support for Astro files develops, you'll find a benefit in being able to see all available icon name values when adding a new icon.
I often like to make sure that icon sizes are governed by the width of their parent. This doesn't work in all projects, but handles basic use cases.
To do this, I put global CSS in my main layout file.
src/layouts/Layout.astro
<style is:global>
svg {
height: auto;
width: 100%;
}
</style>
Here's a super simple demo with a few icons.