{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreigajtddbczb5tp4nwrnmrurwob47msiyvbqwhfr6twznf3syasuzi",
    "uri": "at://did:plc:3okajqf5ifpzwzkuzluxd66m/app.bsky.feed.post/3mjhxqeek7md2"
  },
  "path": "/css-in-svg-symbols.html",
  "publishedAt": "2026-04-13T22:00:00.000Z",
  "site": "https://deterministic.space",
  "tags": [
    "ShadowRoot",
    "developer.mozilla.org\n     ShadowRoot on MDN web docs",
    "Web Components",
    "developer.mozilla.org\n     Web Components on MDN web docs"
  ],
  "textContent": "Styling SVG symbols that are defined using `<symbol id=\"x\">` and included using `<use href=\"#x\">`.\n\n## SVG symbol sprites\n\nIn a web frontend project I’m working on, we need to show a lot of icons in different configurations on a drawing. The symbols are SVGs exported from Figma and they have different layers that can be styled and enabled depending on the symbol’s status. E.g., we want to set the `bg` layer to green for showing the “success” state.\n\nThe structure we have looks like this: We have a `symbols.svg` which is basically just a list of definitions:\n\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\">\n      <defs>\n        <symbol id=\"symbol-42\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\">\n          <circle cx=\"8\" cy=\"8\" r=\"7\" class=\"bg\"/>\n          <!-- ... -->\n        </symbol>\n      </defs>\n    </svg>\n\n\nTo use the symbols, we inline this SVG into our HTML (hidden, so it doesn’t render on its own) and then reference individual symbols by ID:\n\n\n    <svg class=\"symbol-wrap\">\n      <use href=\"#symbol-42\" />\n    </svg>\n\n\nYou can also keep the sprite as an external file and reference it with `<use href=\"symbols.svg#symbol-42\" />`, but inlining avoids CORS issues and is what most bundlers and frameworks do by default.\n\n## It’s a shadow root\n\nNow, naively I thought that styling the symbols would be as simple as writing a little CSS:\n\n\n    .success .symbol-wrap .bg {\n      fill: green;\n    }\n\n\nThis does not work, however. When the symbols get injected, the DOM structure becomes\n\n\n    <svg class=\"symbol-wrap\">\n      <use href=\"#symbol-42\">\n         #shadow-root\n           <symbol id=\"symbol-42\">\n             ...\n\n\nand our CSS selector can’t go past that `#shadow-root`. This is the dev tools indicator for a ShadowRoot \n\n        developer.mozilla.org\n     ShadowRoot on MDN web docs\n , which is (simplified) its own rendering context. This is the system used for implementing Web Components \n\n        developer.mozilla.org\n     Web Components on MDN web docs\n as well.\n\n## Styling inner symbols\n\nWhat can get through to the element in this `ShadowRoot` then? As it turns out, CSS variables! This means we can set `style=\"--bg-fill: green\"` on our `.symbol-wrap` and in our `symbols.svg` we can use it.\n\nThe one missing piece to make this convenient is to, in the `symbols.svg`, add a `<style>` that will pick up the variable and set the properties for our classes:\n\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\">\n      <defs>\n        <style>\n          .bg { fill: var(--bg-fill, currentColor); }\n        </style>\n        <symbol id=\"symbol-42\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\">\n          <circle cx=\"8\" cy=\"8\" r=\"7\" class=\"bg\"/>\n          <!-- ... -->\n        </symbol>\n      </defs>\n    </svg>\n\n\nThe `currentColor` fallback means symbols render sensibly even when no variable is set. They just inherit the text color of their container.\n\nCSS custom properties are the one thing that crosses the `<use>` shadow boundary, so this pattern scales to as many layers and states as you need.",
  "title": "Using CSS vars to style SVG symbols"
}