Skip to content

Instantly share code, notes, and snippets.

@shawnbot
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawnbot/eb40c7801a527e1949e6 to your computer and use it in GitHub Desktop.
Save shawnbot/eb40c7801a527e1949e6 to your computer and use it in GitHub Desktop.
Progressive ARIA tabs in D3
/*
* A very primitive tab system based on ARIA roles:
* http://www.w3.org/TR/wai-aria/roles
*
* This is heavily inspired by Heydon Pickering's Practical ARIA Examples:
* http://heydonworks.com/practical_aria_examples/
*
* Your markup should look something like this:
*
* <div>
* <!-- note: we only look for panels within the tablist's parent -->
* <ul role="tablist">
* <li><a role="tab" aria-selected="true" href="#panel1">Panel 1</a></li>
* <li><a role="tab" href="#panel2">Panel 2</a></li>
* <li><a role="tab" href="#panel1">Panel 3</a></li>
* </ul>
* <section id="panel1">Panel 1</section>
* <section id="panel2">Panel 2</section>
* <section id="panel3">Panel 3</section>
* </div>
*/
d3.selectAll("*[role='tablist']")
.each(function() {
// grab all of the tabs and panels
var tabs = d3.select(this).selectAll("*[role='tab'][href]")
.datum(function() {
var href = this.href,
target = document.getElementById(href.split("#").pop());
return {
selected: this.getAttribute("aria-selected") === "true",
target: target
};
}),
targets = tabs.data()
.map(function(d) {
return d.target;
}),
panels = d3.selectAll("*[role='tabpanel']")
.filter(function() {
return targets.indexOf(this) > -1;
})
.datum(function(d) {
return d || {selected: false};
});
// when a tab is clicked, update the panels
tabs.on("click.tab", function(d) {
d3.event.preventDefault();
tabs.each(function(tab) { tab.selected = false; });
d.selected = true;
update();
});
// update them to start
update();
function update() {
var selected;
tabs
.attr("aria-selected", function(tab) {
if (tab.selected) selected = tab.target;
return tab.selected;
});
panels
.attr("aria-hidden", function(panel) {
panel.selected = (selected === this);
return !panel.selected;
})
.style("display", function(d) {
return d.selected ? null : "none";
});
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<title>Progressive ARIA tabs with D3</title>
<script src="//d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<p>Click the tabs to show and hide panel content.</p>
<div id="container1">
<ul role="tablist">
<li><a role="tab" href="#panel1" aria-selected="true">Panel 1</a></li>
<li><a role="tab" href="#panel2">Panel 2</a></li>
<li><a role="tab" href="#panel3">Panel 3</a></li>
</ul>
<section role="tabpanel" id="panel1">
<h2>Panel 1</h2>
<p>VHS pour-over dreamcatcher slow-carb fugiat est, ex sint. Synth letterpress next level roof party, before they sold out 90's id bitters nulla brunch. Proident est irure viral Marfa single-origin coffee forage, retro crucifix kitsch VHS. Vice qui drinking vinegar commodo chambray +1 seitan, incididunt four dollar toast artisan. Squid seitan chia Etsy. Ullamco sartorial officia biodiesel, cold-pressed craft beer banh mi irony deep v. Fashion axe assumenda gastropub gentrify hoodie, polaroid nihil sapiente semiotics.</p>
</section>
<section role="tabpanel" id="panel2">
<h2>Panel 2</h2>
<p>Freegan ex placeat, ut cornhole flexitarian typewriter officia wayfarers banh mi fixie. Nihil Pinterest aesthetic mollit, Thundercats YOLO paleo post-ironic tousled brunch commodo craft beer duis. Fanny pack listicle seitan lumbersexual aliqua Blue Bottle. Bespoke wayfarers tilde, tempor Portland fixie cray kale chips Vice narwhal retro. Semiotics meh jean shorts reprehenderit Brooklyn. Minim Pinterest nihil laboris viral before they sold out, elit banh mi labore plaid. Post-ironic consectetur ugh listicle, brunch nesciunt direct trade Austin ennui kogi bicycle rights four loko butcher Kickstarter pop-up.</p>
</section>
<section role="tabpanel" id="panel3">
<h2>Panel 3</h2>
<p>Put a bird on it fugiat Thundercats salvia, 90's fixie Blue Bottle Kickstarter DIY nihil organic cray food truck roof party. Craft beer sunt est, put a bird on it meggings commodo dolore proident occaecat duis Shoreditch aesthetic. PBR&B selvage lumbersexual vinyl 8-bit esse, Pinterest nesciunt before they sold out slow-carb delectus. Taxidermy odio single-origin coffee, Odd Future tofu occupy exercitation nisi authentic 3 wolf moon. Duis letterpress aliqua locavore Neutra you probably haven't heard of them esse. Occupy in banjo PBR&B dolor, swag anim vero tattooed Neutra mumblecore ad. Squid asymmetrical master cleanse cronut, seitan cornhole polaroid Thundercats Godard McSweeney's sunt sustainable aliquip eiusmod.</p>
</section>
</div>
<div id="container2">
<ul role="tablist">
<li><a role="tab" href="#panel4" aria-selected="true">Panel 4</a></li>
<li><a role="tab" href="#panel5">Panel 5</a></li>
<li><a role="tab" href="#panel6">Panel 6</a></li>
</ul>
<section role="tabpanel" id="panel4">
<h2>Panel 4</h2>
<p>Quinoa mlkshk mixtape, selvage single-origin coffee skateboard taxidermy esse reprehenderit duis keytar exercitation Pitchfork Vice sed. Four loko duis deserunt, synth anim small batch lo-fi fashion axe occaecat velit. McSweeney's authentic flexitarian aliquip, PBR&B Neutra incididunt biodiesel cupidatat fanny pack gentrify qui messenger bag ut Truffaut. Freegan retro reprehenderit veniam photo booth, magna fugiat letterpress yr church-key in vegan pariatur. Craft beer tote bag semiotics Truffaut freegan PBR. Labore quinoa quis, eiusmod Tumblr Kickstarter irure brunch Portland Etsy kogi laborum eu lumbersexual. Sint mumblecore ea semiotics +1 typewriter.</p>
</section>
<section role="tabpanel" id="panel5">
<h2>Panel 5</h2>
<p>Bitters mumblecore VHS whatever. Selfies occupy street art Pinterest asymmetrical, semiotics do. Viral disrupt ea PBR&B jean shorts. Vice organic hella deserunt, ad cardigan wolf forage ugh jean shorts Tumblr Portland selfies Helvetica synth. Eiusmod distillery cred, biodiesel Etsy banh mi pickled Shoreditch. Vice Odd Future mustache semiotics, asymmetrical High Life nulla direct trade squid jean shorts. Id McSweeney's Pitchfork irony.</p>
</section>
<section role="tabpanel" id="panel6">
<h2>Panel 6</h2>
<p>Truffaut normcore narwhal pug selvage. Pickled hashtag Tumblr nostrud mixtape street art, semiotics ut. Drinking vinegar chillwave eu literally. Heirloom nesciunt chambray, minim vegan sapiente nostrud chillwave brunch Etsy literally ut do jean shorts bitters. Chambray officia eiusmod, non street art consequat McSweeney's readymade photo booth quis squid. Freegan XOXO food truck dolore anim, cliche authentic sartorial nisi wayfarers. Gentrify ennui authentic, pop-up sriracha adipisicing ex literally.</p>
</section>
</div>
</div>
</body>
<script src="aria-tabs.js"></script>
</html>
html {
font-family: "Helvetica Neue", Helvetica, arial, sans-serif;
}
body {
padding: 1rem;
}
h1, h2, p {
margin: 0 0 1rem 0;
}
section p {
margin-bottom: 0;
}
p + p {
text-indent: 4rem;
}
.container {
max-width: 50rem;
margin: 0 auto;
}
ul[role='tablist'],
ul[role='tablist'] li {
display: block;
list-style: none;
margin: 0;
padding: 0;
}
ul[role='tablist'] {
margin-bottom: -1px;
}
ul[role='tablist']:after {
content: " ";
display: block;
clear: both;
height: 0;
}
ul[role='tablist'] li {
display: block;
float: left;
position: relative;
z-index: 1;
margin-right: .25rem;
}
ul[role='tablist'] li a {
font-weight: bold;
text-decoration: none;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
display: block;
background: #f9f9f9;
padding: .25rem .5rem;
border-color: #999;
border-style: solid;
border-width: 1px;
}
ul[role='tablist'] li a[aria-selected='true'] {
border-bottom-color: #f9f9f9;
}
section[role='tabpanel'] {
border-top-right-radius: 4px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border: 1px solid #999;
background: #f9f9f9;
padding: .5rem;
margin-bottom: 1rem;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment