SVG Interactivity

What You’ll Learn
SVGs aren’t just static graphics—you can make them respond to clicks, hover, touch, and keyboard interactions. That’s how modern dashboards, maps, icons, and micro-interactions are built.
This guide shows how to attach events with JavaScript, how to style interactions with CSS (:hover, :focus-visible), and how to make interactive SVG elements accessible.
⚡ Quick Reference — Interactive SVG
clickToggle state, open dialog, navigate
:hoverHighlight shapes with CSS
tabindexMake SVG focusable
aria-labelDescribe interactive controls
pointer-eventsControl what can be clicked
element.addEventListener('click', function () {
// handle interaction
});👀 Live Preview — Hover & Click
These mini demos are always visible. The full, copy-ready examples are below.
Click to Toggle State
A simple interactive SVG button: click (or press Enter/Space) to toggle the rectangle colour. This includes keyboard support and a visible focus ring.
<!DOCTYPE html>
<html>
<head>
<style>
#toggleRect{cursor:pointer;transition:fill 160ms ease,transform 160ms ease}
#toggleRect:hover{transform:translateY(-1px)}
#toggleRect:focus-visible{outline:none}
#toggleRect.is-focus{stroke:#0f172a;stroke-width:3}
</style>
</head>
<body>
<svg width="240" height="160" viewBox="0 0 240 160">
<rect id="toggleRect" x="55" y="35" width="130" height="90" rx="16" fill="#2563eb"
tabindex="0" role="button" aria-label="Toggle rectangle color" />
</svg>
<script>
const rect = document.getElementById('toggleRect');
function toggle() {
const isBlue = rect.getAttribute('fill') === '#2563eb';
rect.setAttribute('fill', isBlue ? '#ef4444' : '#2563eb');
}
rect.addEventListener('click', toggle);
rect.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
toggle();
}
});
rect.addEventListener('focus', function(){ rect.classList.add('is-focus'); });
rect.addEventListener('blur', function(){ rect.classList.remove('is-focus'); });
</script>
</body>
</html>Hover Highlight (CSS) + Tooltip (JS)
A lightweight pattern: use CSS for hover styling and JavaScript only to show contextual information. This keeps the interaction smooth and fast.
<svg width="320" height="160" viewBox="0 0 320 160">
<style>
.chip{cursor:pointer;transition:transform 140ms ease,opacity 140ms ease}
.chip:hover{transform:translateY(-2px);opacity:0.95}
.chip:focus-visible{outline:none}
.chip.is-focus{stroke:#0f172a;stroke-width:3}
</style>
<g id="chipA" class="chip" tabindex="0" role="button" aria-label="Blue chip">
<rect x="32" y="44" width="120" height="72" rx="18" fill="#3b82f6" />
<text x="92" y="86" text-anchor="middle" font-size="14" fill="white" font-family="system-ui,Segoe UI,Arial">Blue</text>
</g>
<g id="chipB" class="chip" tabindex="0" role="button" aria-label="Green chip">
<rect x="168" y="44" width="120" height="72" rx="18" fill="#10b981" />
<text x="228" y="86" text-anchor="middle" font-size="14" fill="white" font-family="system-ui,Segoe UI,Arial">Green</text>
</g>
</svg>
<div id="tip">Hover or focus a chip</div>
<script>
const tip = document.getElementById('tip');
function bindChip(id, msg) {
const el = document.getElementById(id);
if (!el) return;
function show(){ if (tip) tip.textContent = msg; }
el.addEventListener('mouseover', show);
el.addEventListener('focus', function(){ el.classList.add('is-focus'); show(); });
el.addEventListener('blur', function(){ el.classList.remove('is-focus'); });
el.addEventListener('keydown', function(e){
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); show(); }
});
}
bindChip('chipA', 'Blue chip: click to select (demo)');
bindChip('chipB', 'Green chip: click to select (demo)');
</script>🧠 How It Works
Pick a target element
You can attach events to most SVG elements: <rect>, <circle>, <path>, or grouped elements in <g>.
Use CSS for hover/focus
Keep interactions snappy by using CSS for presentation: :hover, :focus-visible, transitions, and transforms.
Attach JS events
Add event listeners like click, mouseover, or pointerdown using JavaScript. Update attributes with setAttribute or toggle CSS classes.
Make it accessible
If it behaves like a button, add tabindex="0" and role="button". Also handle Enter and Space so keyboard users get the same behavior.
Interactive, responsive UI
By combining CSS for visuals and JS for state, SVG becomes a powerful UI building block for the modern web.
💡 Best Practices
Do
- Use CSS for hover animations and transitions whenever possible
- Use
pointercursor to communicate clickability - Add
tabindex,role, andaria-labelfor interactive controls - Prefer
pointerevents (pointerdown,pointerup) for cross-device input - Keep hit targets large enough for touch (44px+ is a good rule)
Don’t
- Rely on hover-only interactions—touch devices don’t have hover
- Make clickable elements with
fill="none"and no stroke (no hit area) - Forget keyboard users when building button-like interactions
- Attach dozens of high-frequency listeners without considering performance
- Hide focus outlines without providing an alternative focus style
Key Takeaways
SVG elements can handle events like HTML elements
Use CSS for hover/focus effects and JS for state changes
Add tabindex and handle Enter/Space for accessibility
pointer-events helps control hit testing and click behavior
Design interactions that work well on mouse, touch, and keyboard
❓ Frequently Asked Questions
click event listener. If it behaves like a button, add tabindex="0", role="button", and handle Enter/Space for keyboard users.:hover and :focus-visible. You can animate fill, stroke, opacity, and transforms.tabindex="0" so it can receive focus, provide an aria-label (or <title>), and handle keydown so Enter and Space activate the same behavior as click.pointer-events settings, and whether your element has a clickable paint region (e.g. it isn’t fill="none" with no stroke). Also ensure the listener is attached after the SVG is in the DOM.Draw Your Next Shape
Continue with SVG lines and learn how to control stroke width, caps, and positioning.
5 people found this page helpful
