-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC Stage 3]: Built-in SVG Components #1035
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @stramel for the hard work! I left some preliminary feedback :)
proposals/0052-svg-components.md
Outdated
<svg width="48" height="48"> | ||
<!-- SVG Content --> | ||
</svg> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we should go in more detail, and explain how the component will behave with width
and height
. For example, given these two cases where we have the same props in a different order, what is the end result?
<>
<Logo size={50} width={20} />
<Logo width={20} size={50} />
</>
I believe it's also fine to consider an error if the two props are incompatible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely agree this deserves more detail around a somewhat tricky prop. I left this as an outstanding question since I wasn't sure the best way to handle the overlap of height/width props & attributes, the size prop and intrinsic size data coming from the image metadata. https://github.com/withastro/roadmap/pull/1035/files#diff-ab3122e95078e177eab4f364380c44e582e73c496b98809d7d5e966f9d09e1f1R247
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whatever logic we decide is best, it is probably worth adding a warning around it if we decide not to apply.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super excited to see this one move forward! Just a quick note on the framing of this when it gets to docs.
Also, for Sprites, do you think explaining the benefits makes sense, or is this perhaps only an implementation detail? I'm not familiar at all so just curious.
thanks, for hard working and supporting <use> as I requested |
Can you explain how you are implementing the |
- **Framework-Specific Docs:** Documentation will also need to address framework-specific usage. This will cover the limitations of the `.svg` imports in popular frameworks like React and Vue, ensuring smooth adoption for developers who are building Astro projects using these frameworks. | ||
- **Code Examples:** The core team can provide boilerplate examples and starter templates that showcase the optimized `.svg` handling. These templates could be adapted for common use-cases, such as building an icon library or optimizing assets for a marketing page. | ||
- **Experimental Flag:** Initially, this feature could be released under an experimental flag in `astro.config.mjs` to gather feedback from early adopters. If the feedback is positive, the feature could later be enabled by default in a future Astro release. | ||
- **Migration Path:** Since this feature is backwards-compatible, no migration will be required for existing projects. Developers can opt into the new functionality by updating their `.svg` imports, but their projects will continue working without any changes if they choose not to adopt the new behavior. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is backwards compatible? Doesn't importing a .svg
file today return the path to the file? What does it do currently?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we're able to make this backwards compatible by assigning the metadata to the component function. (https://github.com/withastro/astro/pull/12067/files#diff-2036fac95cff79ff0745b8b3f58e7b3131492cb4671271d489f423df0226bfc8R53)
importing an .svg
file today returns a metadata object:
import { src, width, height } from '../../icons/logo.svg';
You will still be able to do this in the new implementation.
If a developer removes an SVG element from the DOM (using client-side JS) that holds the symbols (I.e. the source), will that break other SVGs on the page using that symbol? |
Yes, that will break the rest of the SVGs using that symbol. This is one of the nuances to using this sprite setup. Another option would be to put all the symbols into a single SVG that could be placed on the page (perhaps in a layout for simplicity). This would avoid that nuance but would complicate things in the future from a lazy loading perspective, generating the build, and would a slightly more code (though this is probably negligible) |
The user doesn't need to author the SVG in any certain way for it to be used as a sprite. The sprite behavior is:
All future SVGs will not create and add the |
I can imagine this will present some difficult support scenarios, especially if adding a framework-specific way on top of this is a future goal as you've mentioned in the original RFC. Would there be any downside to having a separate SVG defining the Thinking outside the box a bit here, I could imagine a setup like this:
---
import { SvgSymbol } from 'astro:assets' // naming tbd
import Logo from '../assets/logo.svg';
import Layout from './layouts/BaseLayout.astro'
---
<Layout>
<SvgSymbol />
<Logo />
<h1>I'm a cool page</h1>
</Layout> With the above case, a user is specifically opting-in to the sprite behavior and it is clear where it is used. My mind is thinking a bit on how View Transitions were implemented: https://docs.astro.build/en/guides/view-transitions/#adding-view-transitions-to-a-page |
There are more gotchas when using Sprites which is why we should make that opt-in rather than the default. Even with using a Sprite component to hold the aggregate of SVGs on the page.
As I was mentioning previously, this does complicate the implementation, could prove hard for SSR lazy-loading later, and very slight increase in code size. That being said, I think it might be worth it for the trade-off for avoiding an edge-case on the Sprite usage and possible improvement for framework usage. Would love @natemoo-re's thoughts on it. |
Just wanted to say that doing this: ---
import ThumbIcon from '../assets/icons/ui/thumbs-up.svg?raw';
---
<Fragment set:html={ThumbIcon} /> Has been pretty great for me. I like the idea of "it just works" rather than having to find this in the docs. But I'd rather not overcomplicate things if it creates problems elsewhere. |
A QoL thing: It'd be nice if I can style the svg without having to use a |
I'm not quite sure I'm following. Can you provide an example or for details? |
Yes! ---
import RandomSVG from ".@src/imgs/duck_icon.svg";
---
<RandomSVG />
<style>
svg { /* This would target the svg element that this results in. */ }
</style> |
|
||
When a `.svg` file is first imported and rendered in Astro, the system will convert the file into a `<symbol>` element. This will be inserted into the `<svg>` element. This approach ensures that all subsequent renders of that `.svg` can use a `<use>` element, referencing the ID of the initial `<symbol>`. | ||
|
||
This method was chosen by `astro-icon` to optimize SVG usage by default. It is riskier because it does more manipulation to the `.svg` file and relies on the `id` reference being available. The benefit to this method is that we now only have a single definition of repeated usages of the same `.svg` file and only minimal code to reference the definition in other locations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is opt-in only when the user uses <symbol>
, is that right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is opt-in through a prop on the icon or at the config level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wanting to also investigate creating a Sprite
component that would hold all the definitions. This could solve the edge-case of undefined icons. Though I'm not sure if it's possible.
I'm not sure there is much we can do about that. The styling is primarily leaning on the feature-set of Astro. You could use the |
Summary
This RFC proposes adding native support for importing and rendering
.svg
files as Astro components, with optimized rendering techniques to minimize performance impact. It aims to allow.svg
files to be treated as components that accept props and be optimized for repeated use on a page using<symbol>
and<use>
elements.An SVG can be imported directly into an Astro component and used as a component that will only embed itself once.
Results in:
Links