Icon component reference
Icon is the one component svgworm gives you: createIcon(manifest) from @svgworm/react, or the Icon.astro that svgworm init writes. Both read the manifest and render the same markup with no client JavaScript. A test in this repository keeps them in step (ADR-0017). This page covers both.
<Icon name="home" />
<Icon name="home" title="Go home" />
<Icon name="brand/sunset" width={32} height={32} className="logo" />
Props#
| Prop | Type | Default | Meaning |
|---|---|---|---|
name |
IconName |
required | An icon from the manifest. The type is the union of every name, so a typo is a compile error (tsc or astro check) |
title |
string |
Accessible name. Renders a <title> inside the <svg> (or alt / aria-label for the other deliveries) and sets role="img" |
|
label |
string |
Accessible name as aria-label, with role="img". Use title or label, not both; title wins |
|
width, height |
number | string |
1em |
Size. A bare number is pixels. 1em follows the font size of the parent, so an icon next to text scales with it |
className (React), class (Astro) |
string |
Passed to the rendered element, whatever it is | |
style |
React: object. Astro: string or object | Passed to the rendered element. On a mask icon it is merged after the mask declarations, so it can override them | |
| any other SVG prop | SVGProps<SVGSVGElement> minus children, ref, title, name |
id, data-*, aria-*, onClick and so on. On the img and mask deliveries only HTML attributes carry over |
Without title or label the icon is decorative: aria-hidden="true" on the <svg> and the <span>, alt="" on the <img>. The <svg> also gets focusable="false" so old Edge does not tab into it.
Markup per delivery#
The manifest records a delivery per icon (how svgworm works). Icon renders a different element for each. CSS that targets svg reaches only the first one.
use (most icons)#
<svg
focusable="false"
height="1em"
viewBox="0 0 24 24"
width="1em"
aria-hidden="true"
>
<use href="/icons/icons.d907d82b.svg#i-home"></use>
</svg>
The viewBox carries only the icon’s size (0 0 {width} {height}). The symbol in the sprite keeps the full viewBox, including an origin such as 19 19 106 106, so writing your own <svg><use> with the manifest’s viewBox would shift such an icon.
With title="Go home": role="img", no aria-hidden, and <title>Go home</title> before the <use>.
The icon’s paths live in the sprite’s <symbol>. Mono icons are drawn with currentColor, so the color of the <svg> (inherited from the parent) is the icon color.
img (multicolor icons that need gradients, masks, clip paths or filters)#
<img
alt=""
height="1em"
src="/icons/icons.stack.91bff0b3.svg#i-brand--sunset"
width="1em"
/>
The stack file shows the one nested <svg> whose id is the URL fragment. An <img> cannot inherit currentColor, which is fine, because these icons keep their own colors. title or label becomes the alt.
mask (mono icons that need gradients, masks, clip paths or filters)#
<span
aria-hidden="true"
style='display:inline-block;width:1em;height:1em;background-color:currentColor;mask:url("/icons/icons.stack.91bff0b3.svg#i-caf_e9_") center / contain no-repeat'
></span>
The icon is a CSS mask over a currentColor background, so it follows the parent’s color like a use icon. Its size is an inline style. Change it with the width and height props (or style), not with a class.
Sizing#
- The default
1emmakes every delivery follow the parent’sfont-size: a 20 px line gets 20 px icons. widthandheightprops set the size on every delivery:width={24} height={24}orwidth="1.5rem" height="1.5rem".- A CSS rule on a class (
.icon { width: 2rem; height: 2rem }) resizessvgandimgicons, but notmaskicons, whose size is inline. Use the props when the icon may be a mask icon.
Coloring#
- Mono icons: set
coloron the parent (or on the icon throughclassName/class). Mono icons follow it, on both theuseand themaskdelivery. A link that turns red on hover turns its icon red too. - Multicolor icons: they ignore
colorand keep the colors from the SVG file. To make one followcurrentColor, add amonocolor override. svgworm fails the build when the icon has content that cannot follow it. - Do not set
fillorstrokeon the<svg>. The symbol’s own attributes win inside a<use>.coloris the only knob.
Reaching every delivery with CSS#
Give the icon a class and target that, never the element name:
.icon {
vertical-align: -0.125em; /* sits on the text baseline */
flex: none;
}
<Icon name="home" className="icon" />
In Astro the prop is class. Both components put the class on the element they render, whichever it is.
Errors#
- Unknown name: a
namethat is not in the manifest is a type error. At runtime (an untyped name, or a stale manifest) the component throwsUnknown icon "…", with the closest names in React. Unsupported svgworm manifest version: the manifest was written by a newer svgworm than the adapter reads. Update@svgworm/react, or re-runsvgworm initfor a freshIcon.astro.Icon "…" needs the stack file …, but the manifest has none: the manifest is from an older build. Runsvgwormagain.
See Troubleshooting for icons that render blank or in the wrong color.