🔄 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 -->`;
};
This method uses innerHTML to inject SVGs on each toggle. While this works, it has two major drawbacks:
Security Risk:
innerHTML
is prone to XSS (Cross-Site Scripting) attacks and is generally discouraged for dynamic updates.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>
const icon = document.querySelector('#play-toggle-icon use');
const onPlay = () => {
icon.setAttribute('href', '#vjs-icon-play');
};
const onPause = () => {
icon.setAttribute('href', '#vjs-icon-pause');
};
📘 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)