Click SVG Element to Focus (and Style)

Avatar of Chris Coyier
Chris Coyier on

A reader writes in:

Is there anything on your site that shows me how to make an SVG clickable using CSS? As in, I have an SVG and I click on part of it and it should reveal an outline on that part of the element? I have a telephone interview Tuesday for a job as a remote SVG Illustrator and I don’t want to look like a turkey.

Say I have an <svg> of The United States and it’s like this:

<svg class="us" viewBox="0 0 500 400">

  <path d="..." class="wisconsin" />

  <polygon points="..." class="colorado" />

  <g class="michigan">
    <path d="..." class="michigan--up">
    <path d="..." class="michigan--main">
  </g>

  <!-- etc -->

</svg>

Each state then is kind of a direct descendant of the <svg>, the selector would be svg.us > *.

Typically, when I think “clickable”, I think JavaScript. Here’s how we could watch for clicks on each state. We’ll also apply a class to the state clicked:

var allStates = $("svg.us > *");

allStates.on("click", function() {
  
  allStates.removeClass("on");
  $(this).addClass("on");
  
});

That class will do the styling for us. You mentioned an outline, so let’s do that and a fill color as well:

.on {
  fill: pink;
  stroke: red;
  stroke-width: 2;
}

Tada!

See the Pen Click State to Activate by Chris Coyier (@chriscoyier) on CodePen.

But you DID say “clickable using CSS” specifically. That’s a little trickier. Usually we have :focus in CSS, but I don’t think there is any tried-and-true way to make an SVG element itself focusable. There was talk (long ago) of a focusable attribute, but I think that’s out. The HTML-way is tabindex, which I believe works in some browsers, but we can’t count on it. I think the best way is using anchors in SVG (yep, we can use them in SVG too!) which are focusable in all browsers. Then apply the :focus style to the anchor which cascades into the shapes.

Amelia Bellamy-Royds did just this in a StackOverflow thread. Here’s my slightly simplified version:

<svg viewBox="0 0 95 50">
  <a xlink:href="#0">
    <circle cx="20" cy="25" r="5" data-Name="shape 1" data-tabindex="0" />
  </a>
  <a xlink:href="#0">
    <circle cx="40" cy="25" r="5" data-Name="shape 2" data-tabindex="0" />
  </a>
  <a xlink:href="#0">
    <circle cx="60" cy="25" r="5" data-Name="shape 3" data-tabindex="0" />
  </a>
  <a xlink:href="#0">
    <circle cx="80" cy="25" r="5" data-Name="shape 4" data-tabindex="0" />
  </a>
</svg>
a:focus {
  fill: pink;
  stroke: red;
  stroke-width: 1;
}

That should do it:

See the Pen SVG with Focusable Elements by Chris Coyier (@chriscoyier) on CodePen.