10.2 #Navigation.tabs Tab-based nav
Toggle example guides Toggle HTML markup
A list of radio buttons is used to select and show one of several tabs.
Manually entering the hash pointing to one of the elements selects and shows the tab where that element belongs and performs an action on that element.
This is fundamentally a JavaScript module. The only CSS directive is to make all tabs initially not visible.
To set up the tab based navigation, structure the markup as per the example below, and then make the following call:
setupTabs({
// Actions (impure functions, as they read from/write to the global state represented by the HTML):
// - read
getDefaultHash: () => /* string */,
getElemById: id => /* obj */,
getHash: () => /* string */,
getId: e => /* string */,
getParentTab: elem => /* object */,
getTabPage: name => /* object */,
getTabInput: name => /* object */,
getVisibleTabs: () => /* objects */,
isTab: str => /* bool */,
// - write
actionOnElem: e => { /* action */ },
check: cb => { /* action */ },
hide: e => { /* action */ },
show: e => { /* action */ },
setClickCallback: f => { /* action */ },
setHash: h => { /* action */ },
setHashChangeCallback: f => { /* action */ },
tabInputCallback: eventObj => { /* action */ }
});
Note: The example below exercises the logic of the module, but shows it differently:
- tabs are "shown" by boxing them and coloring their contents green
- tabs are "hidden" by removing the box and coloring their contents red
- if an element is selected, it's background is lightgreen
Example
tab 1
- elem 1.1
- elem 1.2
- elem 1.3
tab 2
- elem 2.1
- elem 2.2
- elem 2.3
tab 3
- elem 3.1
- elem 3.2
- elem 3.3
Markup
<script>
(function() {
// Load the script
const script = document.createElement("script");
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js';
script.type = 'text/javascript';
script.addEventListener('load', () => {
console.log(`jQuery ${$.fn.jquery} has been loaded successfully!`);
// use jQuery below
// the stuff above is taken from [1]
$(document).ready(() => {
// some helper function
const prependHash = str => str == '' ? str : '#' + str;
// in this demo shown/hidden are actually mapped to green-and-boxed/red-not-boxed
$('.tab-page').css('display', 'initial');
$('.tab-page').css('color', 'red');
$('.tab-page li').css('display', 'table')
setupTabs({
// - read
getDefaultHash: () => $('nav input[checked]').val().toString(),
getElemById: id => $('#' + id),
getHash: () => prependHash($('#hash').val().toString()),
getId: e => e.attr('id'),
getParentTab: elem => dropDashTab($('#' + elem).parents('.tab-page').attr('id')),
getTabPage: name => $('.tab-page' + '#' + name + '-tab'),
getTabInput: name => $('nav input[value=' + name + ']'),
getVisibleTabs: () => $('.tab-page').filter(
function( index ) {
return this.style.color === 'green';
}
),
isTab: str => $('#' + str).filter('.tab-page').length != 0,
// - write
actionOnElem: e => {
$('.tab-page li').css('font-weight', 'normal');
$('.tab-page li').css('background-color', 'transparent');
e.css('font-weight', 'bold');
e.css('background-color', 'lightgreen');
},
check: cb => { cb.prop('checked', true); },
hide: e => {
$('.tab-page li').css('font-weight', 'normal');
$('.tab-page li').css('background-color', 'transparent');
e.css('color', 'red');
e.children().first().css('border-style', 'none');
},
show: e => {
$('.tab-page li').css('font-weight', 'normal');
$('.tab-page li').css('background-color', 'transparent');
e.css('color', 'green');
e.children().first().css('border-style', 'solid');
},
setClickCallback: f => { $('nav input').click(f); },
setHash: h => { $('#hash').val(h); },
setHashChangeCallback: f => { $('#hash').change(f); },
tabInputCallback: eventObj => {
$('#hash').val($(eventObj.currentTarget).val().toString()).change();
}
});
$('#hash').change();
});
// the stuff below is taken from [1]
});
document.head.appendChild(script);
})();
// [1]: https://stackoverflow.com/a/10113434/5825294
</script>
<label for="name">URL:</label>
<input type="text"
value="sch://some/url/#"
minlength="0" maxlength="8" size="10"
readonly>
<input type="text"
id="hash"
name="name"
placeholder="hash (without the leading #)">
<nav>
<ul>
<li>
<input type="radio" name="nav-tabs" id="tab1-radio" value="tab1">
<label for="tab1-radio">show only tab 1</label>
</li>
<li>
<input type="radio" name="nav-tabs" id="tab2-radio" value="tab2" checked>
<label for="tab2-radio">show only tab 2 (this is the default)</label>
</li>
<li>
<input type="radio" name="nav-tabs" id="tab3-radio" value="tab3">
<label for="tab3-radio">show only tab 3</label>
</li>
</ul>
</nav>
<div>
<div class="tab-page" id="tab1-tab">
tab 1
<ul>
<li id="elem11">elem 1.1</li>
<li id="elem12">elem 1.2</li>
<li id="elem13">elem 1.3</li>
</ul>
</div>
<div class="tab-page" id="tab2-tab">
tab 2
<ul>
<li id="elem21">elem 2.1</li>
<li id="elem22">elem 2.2</li>
<li id="elem23">elem 2.3</li>
</ul>
</div>
<div class="tab-page" id="tab3-tab">
tab 3
<ul>
<li id="elem31">elem 3.1</li>
<li id="elem32">elem 3.2</li>
<li id="elem33">elem 3.3</li>
</ul>
</div>
</div>
Source:
css/modules/tabs.css
, line 1