How to Store State in SVG Using Data Attributes
Storing application state directly within SVG elements is a practical
way to manage interactive vector graphics without maintaining complex
external mappings. By utilizing standard HTML5 data-*
custom attributes, developers can bind metadata, status flags, and
configuration values directly to SVG shapes like
<path>, <circle>, and
<g>. This article covers how to embed
data-* attributes into SVG markup, read and modify them
using JavaScript, and leverage CSS attribute selectors for state-driven
rendering.
Adding
data-* Attributes to SVG Markup
SVG 2 fully supports data-* attributes on all graphic
and structural elements. You can declare them directly in the SVG source
code just as you would on any standard HTML element.
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<circle
id="node-1"
cx="50"
cy="50"
r="30"
data-node-id="101"
data-status="idle"
data-capacity="75"
/>
<circle
id="node-2"
cx="150"
cy="50"
r="30"
data-node-id="102"
data-status="active"
data-capacity="100"
/>
</svg>Reading and Updating State with JavaScript
You can access and update these values dynamically using the DOM
dataset API or the standard getAttribute and
setAttribute methods.
Using the dataset API
The dataset property converts hyphenated attribute names
into camelCase properties.
const node = document.querySelector('#node-1');
// Reading state
console.log(node.dataset.nodeId); // "101"
console.log(node.dataset.status); // "idle"
// Updating state
node.dataset.status = "active";
node.dataset.capacity = "80";Using
getAttribute and setAttribute
If you need to maintain explicit attribute strings or support older environments, standard attribute methods work identically:
const node = document.querySelector('#node-1');
// Reading state
const currentStatus = node.getAttribute('data-status');
// Writing state
node.setAttribute('data-status', 'error');Styling SVG Elements Based on State
Binding state directly to SVG nodes enables state-driven styling through CSS attribute selectors, removing the need to manually toggle class names or manipulate inline styles.
/* Default state */
circle[data-status="idle"] {
fill: #94a3b8;
stroke: #64748b;
}
/* Active state */
circle[data-status="active"] {
fill: #22c55e;
stroke: #16a34a;
}
/* Error state */
circle[data-status="error"] {
fill: #ef4444;
stroke: #dc2626;
}Example: Interactive Toggle Node
Below is a complete implementation showing how an SVG element toggles its own state and responds to user interaction:
<svg width="100" height="100" viewBox="0 0 100 100">
<rect
id="toggle-btn"
x="10"
y="10"
width="80"
height="80"
rx="8"
data-active="false"
/>
</svg>
<style>
#toggle-btn {
cursor: pointer;
transition: fill 0.2s ease;
}
#toggle-btn[data-active="false"] {
fill: #cbd5e1;
}
#toggle-btn[data-active="true"] {
fill: #3b82f6;
}
</style>
<script>
const button = document.getElementById('toggle-btn');
button.addEventListener('click', () => {
const isCurrentlyActive = button.dataset.active === 'true';
button.dataset.active = (!isCurrentlyActive).toString();
});
</script>Important Considerations
- Type Conversion: All values in
data-*attributes are stored as strings. Boolean and numeric values must be parsed explicitly (e.g., viaparseInt()or strict comparison=== 'true'). - Complex State: For objects or arrays, serialize
data using
JSON.stringify()when writing to an attribute andJSON.parse()when reading it. - Inline vs. External SVGs:
data-*attributes can only be manipulated via standard JavaScript if the SVG is embedded inline in the DOM or inside an<object>tag accessible across domains. SVGs loaded via<img>tags cannot be modified via JavaScript.