Three ways to put an SVG icon in HTML
Compare the img tag, inline svg and CSS backgrounds or masks for SVG icons, with code, and see how each handles caching, styling, accessibility and IDs.
5 min read
You have an SVG file of a token logo and an HTML page. There are three practical ways to connect them: an <img> element, the <svg> markup pasted inline, or a CSS property that points at the file. All three render the same picture, but they behave very differently once you need caching, color changes, screen reader support or fifty icons on one page.
Here is each method with a minimal example, followed by a comparison and some rules for choosing.
1. The img element
<img src="/icons/eth.svg" width="24" height="24" alt="Ethereum" />
This is the simplest option and often the right one. The browser fetches the file once, caches it, and reuses it wherever the same URL appears. Adding loading="lazy" defers icons that start off-screen, which helps on long token lists.
The SVG is treated as an image document. It cannot run scripts, cannot load other external resources, and cannot be styled by your page's CSS. Its internal id values are isolated, so the same file can appear a hundred times without conflicts.
The cost is flexibility. You can't change its fill color with CSS, and currentColor inside the file doesn't pick up your text color. If you need a white version and a dark version, you need two files.
Always set width and height attributes. They let the browser reserve space before the file loads, which prevents the row from jumping when the icon arrives.
For alt, describe what the icon tells the reader. A logo standing alone gets the asset name. A logo sitting next to the text "Ethereum" repeats that text, so it should be alt="" to keep screen readers from announcing it twice. The decorative or informative guide covers this choice in more detail.
2. Inline svg
<button type="button" class="network">
<svg width="20" height="20" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M12 3 6.4 12.2 12 15.4l5.6-3.2z" />
</svg>
Ethereum
</button>
Pasting the markup into the page makes the SVG part of the document. Its shapes are DOM elements, so your CSS reaches them: you can set fill, animate on hover, or use fill="currentColor" so the icon follows the button's text color in every state and theme.
.network { color: #c9ccd3; }
.network:hover { color: #ffffff; }
There is no extra network request, which is good for a few icons above the fold. It turns into a cost when icons repeat. A 3 KB logo inlined in each row of a 100-row token table adds about 300 KB to the HTML before compression, and none of it can be cached separately from the page.
Two other things change when SVG is inline.
IDs share the page's namespace. Many logos define a gradient or clip path with an id and refer to it with url(#id). If two inline icons both define id="a", every url(#a) points to whichever comes first in the document. When that first icon is hidden with display: none or removed, the gradient in the second one can disappear. Give each icon's IDs a unique prefix; the SVG ID collisions guide shows how.
Scripts can run. Inline SVG is part of your page, so a <script> element or an event handler attribute such as onload inside it can execute, depending on how the markup gets into the page. Only inline SVG you trust, or sanitize it first.
For accessibility, hide a decorative icon with aria-hidden="true", as in the button above, where the text already names the network. For an icon that carries meaning on its own, give it a role and a name:
<svg role="img" aria-label="Base" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z" />
</svg>
3. CSS background-image and mask-image
<span class="icon icon-eth"></span>
.icon {
display: inline-block;
width: 24px;
height: 24px;
background: center / contain no-repeat;
}
.icon-eth { background-image: url("/icons/eth.svg"); }
The file is cached like an <img>, and the HTML stays short. This suits decorative icons that come and go with a class name, such as a chain badge that changes when the user switches networks.
mask-image turns the same idea into a recoloring tool. The file's shape becomes a stencil, and background-color fills it:
.icon-mono {
display: inline-block;
width: 24px;
height: 24px;
background-color: currentColor;
mask: url("/icons/eth-mono.svg") center / contain no-repeat;
}
That gives a single-color icon any color, including the current text color, without inlining it. It only makes sense for mono artwork, since every opaque pixel takes the same color. Details, prefixes and browser support are in the CSS mask guide.
The weakness of both CSS methods is that the icon is not content. There is no alt, so screen readers get nothing unless you add text or an ARIA label to the element. Browsers usually leave out background images when printing unless the user turns on background graphics. And in Windows forced colors mode, background colors are replaced, which can make a masked icon vanish or change color.
Side by side
| img | Inline svg | CSS background or mask | |
|---|---|---|---|
| Cached separately | Yes | No, part of the HTML | Yes |
| Styled by page CSS | No | Yes | Mask color only |
Follows currentColor |
No | Yes | Mask, via background-color: currentColor |
| Text alternative | alt |
aria-label or <title> |
Must be added to the element |
| ID collisions | Isolated | Shares the page's IDs | Isolated |
| Scripts in the file | Don't run | Run | Don't run |
| Lazy loading | loading="lazy" |
Not available | Fetched once a rendered element uses the rule |
Choosing between them
For full-color brand logos, especially many of them, use <img>. Token lists, market tables and exchange directories fall here. The logos keep their official colors, caching does the heavy lifting, and IDs never clash.
For interface icons that should follow text color and hover states, use inline SVG. If the same few icons repeat across a page, consider a sprite with <symbol> and <use>, which keeps one copy of each shape in the document; see SVG sprites.
For single-color icons you want to recolor without inlining them, use a CSS mask. For purely decorative images tied to a class or state, a background image is fine.
Mixing methods on one page is normal. A wallet can show token logos with <img>, draw its navigation icons inline, and use a mask for the small chain badge in the header.