JSFiddle - React, Tailwind, and code Playground
by Alex Alex
HTML
<ul role="tablist" class="tabs">
<li><a role="tab" aria-controls="dizzy" class="tab" href="#dizzy">Dizzy</a></li>
<li><a role="tab" aria-controls="ninja" class="tab" href="#ninja">Ninja</a></li>
<li><a role="tab" class="tab" aria-controls="missy" href="#missy">Missy</a></li>
</ul>
<div role="tabpanel" class="panel" id="dizzy">
<img src="https://jsbin-user-assets.s3.amazonaws.com/rem/dizzy.jpg" alt="Photo of Dizzy">
<dl>
<dt>Name</dt>
<dd>Dizzy</dd>
<dt>Colour</dt>
<dd>Tabby</dd>
<dt>Super power</dt>
<dd>Sleeping</dd>
</dl>
</div>
<div role="tabpanel" class="panel" id="ninja">
<img src="https://jsbin-user-assets.s3.amazonaws.com/rem/ninja.jpg" alt="Photo of Ninja">
<dl>
<dt>Name</dt>
<dd>Lord Ninja of Catville</dd>
<dt>Colour</dt>
<dd>Black & White</dd>
<dt>Super power</dt>
<dd>Most pathetic meow known to catkind</dd>
</dl>
</div>
<div role="tabpanel" class="panel" id="missy">
<img src="https://jsbin-user-assets.s3.amazonaws.com/rem/missy.jpg" alt="Photo of Missy">
<dl>
<dt>Name</dt>
<dd>Missy</dd>
<dt>Colour</dt>
<dd>Black</dd>
<dt>Super power</dt>
<dd>Computer hardware protection</dd>
</dl>
</div>
<small>The following content is demonstrate the effects of a tall page.</small>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi excepturi molestias modi sed harum, assumenda, cupiditate deleniti magni eaque velit quidem voluptate mollitia, consequatur sit sint quos dolorum perspiciatis omnis!</p>
<a href="#top">top</a
CSS
* { margin: 0; padding: 0; }
body { font-family: helvetica; margin: 20px; }
img {
position: relative;
border: 3px solid #000;
height: 200px;
width: 300px;
object-fit: cover;
}
ul {
margin: 0;
padding: 0;
list-style: none;
overflow: hidden;
margin-bottom: 10px;
}
.panel {
border: 1px solid #ccc;
overflow: scroll;
margin-bottom: 10px;
}
ul a {
border: 1px solid #ccc;
padding: 10px;
margin-right: 10px;
float: left;
display: block;
}
ul a {
color: #000;
text-decoration: none;
}
ul.tabs a:hover {
background: #000;
border-color: #000;
color: #fff;
}
ul.tabs a.selected,
ul.tabs a[aria-selected='true'] {
background: #ccc;
border-color: #ccc;
color: #000;
/* color: #fff; */
}
.panel {
padding: 10px;
width: 550px;
overflow: hidden;
}
div[aria-hidden='true'] {
display: none;
}
dl {
float: right;
width: 180px;
}
dt {
font-weight: bold;
}
dd {
color: #666;
font-style: italic;
margin-bottom: 5px;
margin-left: 10px;
}
p {
line-height: 200px;
width: 100px;
}
JavaScript
/*global $*/
// a temp value to cache *what* we're about to show
var target = null;
// collect all the tabs
var tabs = $('.tab').on('click', function () {
console.log('click')
target = $(this.hash).removeAttr('id');
if (location.hash === this.hash) {
setTimeout(update);
}
}).attr('tabindex', '0');
// get an array of the panel ids (from the anchor hash)
var targets = tabs.map(function () {
return this.hash;
}).get();
// use those ids to get a jQuery collection of panels
var panels = $(targets.join(',')).each(function () {
// keep a copy of what the original el.id was
$(this).data('old-id', this.id);
});
function update() {
console.log('update')
if (target) {
target.attr('id', target.data('old-id'));
target = null;
}
var hash = window.location.hash;
if (targets.indexOf(hash) !== -1) {
return show(hash);
}
// NOTE: this was added after the article was written
// to fix going "back" on the browser nav to an empty state
if (!hash) {
show();
}
}
function show(id) {
// if no value was given, let's take the first panel
if (!id) {
id = targets[0];
}
// remove the selected class from the tabs,
// and add it back to the one the user selected
tabs.removeClass('selected').attr('aria-selected', 'false').filter(function () {
return (this.hash === id);
}).addClass('selected').attr('aria-selected', 'true');
// now hide all the panels, then filter to
// the one we're interested in, and show it
panels.hide().attr('aria-hidden', 'true').filter(id).show().attr('aria-hidden', 'false');
}
window.addEventListener('hashchange', update);
// initialise
if (targets.indexOf(window.location.hash) !== -1) {
update();
} else {
show();
}