I used the component solution Laaouatni Anas suggests, utilizing sveltekit+vite's ability to handle raw files and import them as the actual raw contents themselves.
The Problem
One caveat of Laaouatni Anas's component solution (not the original answer) was that it if I imported the component on the client side even with ssr it sometimes would need to fetch the actual svg via a call. Which is great in terms of loading up the bulk of everything first, but it takes a small amount of time to fetch the svg. So there would usually be a slight delay in rendering the svg. Which did not look good when first loading up the site.
Another thing to keep in mind you should be careful of this method, as using the @html tag to load in content that isn't scanned potentially opens up highjacking purposes to malicious users.
My Solution
Instead of loading up the svg via a call and passing args for the filepath to the svg I created a seperate file to store the icons raw:
import chevronRightSolid from '$lib/assets/chevron-right-solid.svg?raw';
export const rawIcons = {
chevronRightSolid: chevronRightSolid
};
As you add new icons you will need to update the file and add them, but compared to creating a component file for every single icon and exporting that this feels like a more sane answer.
Then create the actual icon component, importing the rawIcons, which allows it to just be cached once so you don't store duplicates of the raw svg code.
<script lang="ts">
import { rawIcons } from '$lib/resources/icon.resources';
export let icon: keyof typeof rawIcons;
export let width = '20px';
export let height = '20px';
export let fill = '#000';
</script>
<div
style="--width:{width};
--height: {height};
--fill:{fill};">
{@html rawIcons[icon]}
</div>
<style>
div {
width: var(--width);
height: var(--height);
fill: var(--fill);
display: flex;
justify-content: center;
align-items: center;
}
</style>
Keep in mind
Laaouatni Anas's solution with lots of svgs might be better for certain use cases. My use case was that I did not need ssr and I was building the project for a capacitor svelte app. This enabled me to just bundle everything and send that all to the user basically all at once. If you send the user the RawIcons file and you have hundreds of icons it could take a little longer to load, increasing load times.
Edit
To fix a bug regarding safari where default width/height doesn't appear to be 100% you might need to either modify every single svg component that you download. Or you could add this script to modify the component:
<script lang="ts">
import { rawIcons } from '$lib/resources/icon.resources';
export let icon: keyof typeof rawIcons;
export let width = '20px';
export let height = '20px';
export let fill = '#000';
function addStylesToSVG(svgString: string) {
// Ensure the SVG string starts with an <svg> tag
if (!svgString.startsWith('<svg')) return svgString;
return (
`<svg style='width: ${width}; height: ${height}; fill: ${fill};' ` + svgString.slice?.(4)
);
}
</script>
{@html addStylesToSVG(rawIcons[icon])}
<style>
</style>
Or depending on your project, if you don't have other svgs you're worried about. You could just add a global style for svgs to default it to what chrome does
:global(svg) {
width: 100%;
height: 100%;
}
<img src={Logo} />
But I still want to solve this component issue because it is useful in array rendering and so on. – Precaution