DEV Community

Cover image for Best Practices for Using Dynamic SVGs in Your Frontend
Damandeep Singh
Damandeep Singh

Posted on • Edited on

Best Practices for Using Dynamic SVGs in Your Frontend

🔄 How often have you needed to update icons dynamically based on user interaction?

Whether it's toggling a button state, switching themes, or updating a UI element, dynamically updating icons is a common need in frontend development.

🚫 Naive Approach :-

const button = document.getElementById('play-toggle');

const onPlay = () => {
  button.innerHTML = `<!-- SVG markup for play icon -->`;
};

const onPause = () => {
  button.innerHTML = `<!-- SVG markup for pause icon -->`;
};
Enter fullscreen mode Exit fullscreen mode

This method uses innerHTML to inject SVGs on each toggle. While this works, it has two major drawbacks:

  1. Security Risk: innerHTML is prone to XSS (Cross-Site Scripting) attacks and is generally discouraged for dynamic updates.

  2. Performance Overhead: Even if replaced with appendChild() or similar safer methods, this approach re-renders the entire SVG each time, leading to unnecessary DOM updates.


✅ Efficient & Safe Approach :-

A cleaner, more efficient, and secure solution is to define your SVGs once using <symbol> and reference them dynamically using <use>.

Checkout the code below:-

<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
    <defs>
      <symbol id="vjs-icon-play" viewBox="0 0 512 512">
        <path fill="currentColor" d="M108.9 66.5v353L403 242.1zm25.3 49.1 212.3 126.7-212.3 128z"></path>
      </symbol>
      <symbol id="vjs-icon-pause" viewBox="0 0 512 512">
        <path fill="currentColor" d="M98.2 422.5h121.6v-359H98.2zm20.4-  338.7h80.8v318.4h-80.8zm173.6-20.3v359h121.6v-359zm101.2 338.7h-80.8V83.8h80.8z">
        </path>
      </symbol>
    </defs>
</svg>


<!-- Play/Pause Toggle Button -->
<button id="play-toggle">
  <svg id="play-toggle-icon" viewBox="0 0 512 512" width="32" height="32">
    <use href="#vjs-icon-play"></use>
  </svg>
</button>
Enter fullscreen mode Exit fullscreen mode
const icon = document.querySelector('#play-toggle-icon use');

const onPlay = () => {
  icon.setAttribute('href', '#vjs-icon-play');
};

const onPause = () => {
  icon.setAttribute('href', '#vjs-icon-pause');
};

Enter fullscreen mode Exit fullscreen mode

📘 Quick Reference :-

ℹ <defs> : It is an SVG container used to store elements such as <symbol>, <gradient>, <filter>, etc., that are not rendered directly in the SVG output. Instead, these definitions can be referenced later by other SVG elements.

ℹ <symbol> : It is an SVG element used to define reusable graphic content — such as icons, shapes, or patterns — without rendering it immediately.

ℹ <use> : It is an element in SVG which is designed to reference and reuse other SVG elements—especially things like icons, shapes, or graphic elements—without duplicating code.


💡 Why This Approach Is Better?

✅ Security: No innerHTML, hence safer from injection attacks.

✅ Performance: The SVG is only defined once; only the reference (href) changes on interaction.

✅ Maintainability: Centralised icon definitions make it easy to manage and scale.



Let me know what do you think about this?

Top comments (0)