Support SVG symbols?
See original GitHub issueI just realized that SVG symbols and inlined CSS are two very similar problems with very similar solutions. I wonder if styled-components can be made to handle SVG symbol management as well.
SVG symbols are very useful, they give you scalable icons that can be styled/colored with CSS, with low bandwidth use. To use them, there needs to be a symbol definition somewhere in the page, and then where you want to use it you put a <svg><use xlinkHref={iconId}/></svg>
. The svg
can be styled with CSS to change colors etc.
So how about something like
import ArrowSvg from '../icons/arrow.svg'
export const Arrow = styled.svgSymbol(ArrowSvg)`
${p => p.left && "transform: rotate(180deg);"}
&:hover { fill: "yellow"; }
`
and later
<p><Arrow/> Styled-components is awesome! <Arrow left/></p>
which becomes this DOM:
<head><style>.a {...}.b{...}</style></head>
<body>
<svg><symbol id="s">...</symbol></svg>
<p>
<svg class="a"><use xlink:href="#s"/></svg>
Styled-components is awesome!
<svg class="b"><use xlink:href="#s"/></svg>
</p>
</body>
So behind the scenes, styled-components would maintain the <svg/>
block with the symbol definitions and come up with a global iconId
for the <use/>
.
The ArrowSvg
content could be from loading with https://github.com/jhamlet/svg-react-loader or something similar.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:3
- Comments:14 (12 by maintainers)
These days IMO best way to handle SVG/icons is with react components:
This way tree-shaking, code-splitting, etc. can ensure only the icons that are being used on a given view are downloaded.
You can then use props to configure any details of the icon (such as colors) on the fly.
Unlike with
<use>
, icons load instantly with the rest of the view from SSR.<use>
blinks terribly when anything causes your parent component to re-render, for example global header logos/icons when transitioning routes.Your JSX linting can cover the SVGs.
Lots of benefits.
Even when the SVG file is cached, anytime the surrounding DOM is manipulated/rerendered, the browser throws away the image and renders it all over again. This looks like a blink where for a few milliseconds the image collapses/becomes invisible, then displays again. If you use Next.js, and have a logo in a global header component in your page components, when routing between pages the browser re-renders the logo with a blink every transition.
Even if browsers optimized this behavior, SVG components will always look better when first loading a SSR page. They don’t load with a blink after the page displays like with
<use>
.I don’t have a blinking demo handy sorry, because I refactored
<use>
to SVG components accross our site a few months ago.True, but gzip handles repetition really well making it a non-issue.
1 “bullet”:
30 “bullets”:
If you are using
<use>
the traditional way, with a large-ish staticicons.svg
file pulled in globally only to use a few icons on the two pages a visitor views, there is more sent down the wire than if you just repeated a few inline SVGs (which often don’t repeat anyway).At the end of the day, there are things you can do with SVG components you simply can’t with
<use>
, like dynamic content, animations and styles.