← Home

🖼️ Astro SVG

I needed to embed SVG icons into an Astro project I’m working on.

This great blog post “Using SVGs as Astro components and inline CSS” by Dave Warrington got me most of the way, but I made a few tweaks to update some deprecated arguments and cut it down a bit.

Below is the final code I used.

Example usage

---
import Icon from "@/components/icon.astro";
---
<Icon icon="question" width="2em" />

icon.astro

---
import { parse } from "node-html-parser";
import type { HTMLAttributes } from "astro/types";

export interface Props extends HTMLAttributes<"svg"> {
  icon: string;
}

async function getSVG(name: string) {
  const filepath = `../../public/img/${name}.svg`;
  const files = import.meta.glob<string>("../../public/img/**/*.svg", {
    query: "?raw",
    import: "default",
  });

  if (!(filepath in files)) {
    throw new Error(`${filepath} not found`);
  }

  const content = await files[filepath]();
  const root = parse(content);
  const svg = root.querySelector("svg");
  const { attributes, innerHTML } = svg || {};

  return {
    attributes,
    innerHTML,
  };
}

const { icon, ...rest } = Astro.props as Props;
const { attributes, innerHTML } = await getSVG(icon);
---

<svg {...attributes} {...rest} set:html={innerHTML} />
← Home