Preface
Goal: Adding javascript interactivity. Exploring DOM.
This is basically just, a tabs component with javascript interactivity.
Examples
For tutorial purpose we need three layouts:
-
Simple layout, to example of oldschool javascript.
-
Simple layout, to explain unobtrusive javascript.
-
Enhance layout, as real live example.
This article cover the last two parts only. As we have already discuss about the first part in the previous article.
Simple Tabs Unobtrusive: Structure
Can you see?
Inline javascript is annoying.
We can add as many event as we want.
After a while the HTML
looks mess.
We need to find a way to make the structure looks tidy.
Document: HTML Head
We can add the javascript at the beginning. We still can reuse previous stylesheet.
<link rel="stylesheet" type="text/css"
href="../css/02-simple-layout.css">
<script src="../js/custom/unobtrusive-simple.js"></script>
Document: HTML Body: Tab Headers
No inline javascript now. The javascript is unobtrusive.
<div class="tab-headers">
<div data-target="home" data-color="bg-blue-500">Home</div>
<div data-target="team" data-color="bg-teal-500"
class="active">Team</div>
<div data-target="news" data-color="bg-red-500">News</div>
<div data-target="about" data-color="bg-orange-500">About</div>
</div>
Document: HTML Body: Tab Content
Now we have a chance to explore more elements.
Using four items, each with their own id
s.
<div class="tab-contents">
<div id="home">
<h3>Home</h3>
<p>Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Quisque in faucibus magna.</p>
</div>
<div id="team">
<h3>Team</h3>
<p>Nulla luctus nisl in venenatis vestibulum.
Nam consectetur blandit consectetur.</p>
</div>
<div id="news">
<h3>News</h3>
<p>Phasellus vel tempus mauris,
quis mattis leo.
Mauris quis velit enim.</p>
</div>
<div id="about">
<h3>About</h3>
<p>Interdum et malesuada fames ac ante
ipsum primis in faucibus.
Nulla vulputate tortor turpis,
at eleifend eros bibendum quis.</p>
</div>
</div>
Simple Tabs Unobtrusive: Javascript
This is basically the same with the previous one. With some additional stuff.
Javascript: DOM Event
How can I put the the external javascript between <head>...</head>
,
instead of put it below?
This simply by wrapping the codes,
inside an event called DOMContentLoaded
.
document.addEventListener('DOMContentLoaded', function(event) {
// code here …
});
Javascript: Managing Contents
By selecting the id
of the content,
we can toggle the visibility.
Array.from(tabHeaders.children).forEach((targetHeader) => {
// Tab Headers: All Click Events
targetHeader.addEventListener('click', () => {
const targetName = targetHeader.dataset.target;
const colorClass = targetHeader.dataset.color;
const targetContent = document.getElementById(targetName);
// …
// Showing the content
Array.from(tabContents.children).forEach((tabContent) => {
tabContent.style.display = 'none';
});
targetContent.style.display = 'block';
targetContent.classList.add(colorClass);
});
});
Javascript: Fat Arrow
You may notice the fat arrow here:
Array.from(tabHeaders.children).forEach((targetHeader) => {
// ..
});
It is a shortcut to previously written function
:
// Set all to default setting
Array.from(tabHeaders.children)
.forEach(function(tabHeader) {
// ..
});
Javascript: Complete
The complete javascript is here below:
document.addEventListener('DOMContentLoaded', function(event) {
const tabHeaders = document.getElementsByClassName('tab-headers')[0];
const tabContents = document.getElementsByClassName('tab-contents')[0];
Array.from(tabHeaders.children).forEach((targetHeader) => {
// Tab Headers: All Click Events
targetHeader.addEventListener('click', () => {
const targetName = targetHeader.dataset.target;
const colorClass = targetHeader.dataset.color;
const targetContent = document.getElementById(targetName);
// Set all to default setting
Array.from(tabHeaders.children).forEach((tabHeader) => {
tabHeader.classList.remove('active');
tabHeader.classList.remove(tabHeader.dataset.color);
tabHeader.classList.add('bg-gray-700');
});
// Except the chosen one
targetHeader.classList.add('active');
targetHeader.classList.remove('bg-gray-700');
targetHeader.classList.add(colorClass);
// Showing the content
Array.from(tabContents.children).forEach((tabContent) => {
tabContent.style.display = 'none';
});
targetContent.style.display = 'block';
targetContent.classList.add(colorClass);
});
});
// Tab Headers: Default
tabHeaders.getElementsByClassName('active')[0].click();
});
Preview
Now we have proper color for the right content.
Each time you click the left tab, the color on the right will be changed.
Enhanced Tabs Unobtrusive: Structure
How about real live component?
Document: HTML Head
We can add the javascript at the beginning. We still can reuse previous stylesheet.
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tabs - Unobtrusive Javascript</title>
<link rel="stylesheet" type="text/css" href="../css/02-enhanced-layout.css">
<link rel="stylesheet" type="text/css" href="../css/03-background-colors.css">
<link rel="stylesheet" type="text/css" href="../css/02-border-radius.css">
<script src="../js/custom/unobtrusive-enhanced.js"></script>
Document: HTML Body: Tab Headers
We have the third level div
.
<div class="tab-headers">
<div data-target="home" data-color="bg-blue-500"> <div>Home</div></div>
<div data-target="team" data-color="bg-teal-500" class="active">
<div>Team</div></div>
<div data-target="news" data-color="bg-red-500"> <div>News</div></div>
<div data-target="about" data-color="bg-orange-500"><div>About</div></div>
</div>
<div class="tab-spacer"></div>
With additional tab-spacer
.
Document: HTML Body: Tab Content
We also have the third level div
here.
<div class="tab-contents">
<div id="home"><div class="tab-content">
<h3>Home</h3>
<p>Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Quisque in faucibus magna.</p>
</div></div>
<div id="team"><div class="tab-content">
<h3>Team</h3>
<p>Nulla luctus nisl in venenatis vestibulum.
Nam consectetur blandit consectetur.</p>
</div></div>
<div id="news"><div class="tab-content">
<h3>News</h3>
<p>Phasellus vel tempus mauris,
quis mattis leo.
Mauris quis velit enim.</p>
</div></div>
<div id="about"><div class="tab-content">
<h3>About</h3>
<p>Interdum et malesuada fames ac ante
ipsum primis in faucibus.
Nulla vulputate tortor turpis,
at eleifend eros bibendum quis.</p>
</div></div>
</div>
Enhanced Tabs Unobtrusive: Javascript
This is also an enhancement of the previous script. With some additional event, to mimic the mouse hover.
Javascript: Managing Headers
Managing third level div
can be done adding bg-white
class.
// Set all to default setting
Array.from(tabHeaders.children).forEach((tabHeader) => {
// …
tabHeader.firstElementChild.classList.remove('bg-white');
});
// Except the chosen one
// …
targetHeader.firstElementChild.classList.add('bg-white');
Javascript: Managing Contents
It is exactly the same with the simple tabs layout. No code is changed here.
Preview
Javascript: Mimic Hover
We can utilize this event:
-
onmouseenter
: add classis-hovered
, and -
onmouseleave
: remove classis-hovered
.
Both can be implemented as below:
// Tab Headers: Mimic All Hover Events
targetHeader.addEventListener('mouseenter', () => {
const targetName = targetHeader.dataset.target;
const targetContent = document.getElementById(targetName);
targetContent.firstElementChild.classList.add('is-hovered');
});
targetHeader.addEventListener('mouseleave', () => {
const targetName = targetHeader.dataset.target;
const targetContent = document.getElementById(targetName);
targetContent.firstElementChild.classList.remove('is-hovered');
});
While the stylesheet has been previously written as:
.tab-headers div.active div:hover {
background-color: #e0e0e0;
}
.tab-contents div div.is-hovered {
background-color: #e0e0e0;
}
Preview
Now whenever the mouse hovering the active
tabs,
we can see something as below:
Javascript: Complete Code
Too long?
Plain javascript is still an option, if you do not want to use framework. It safe, supported in most browser, but not cool for kids these days.
As a conclusion, we can summarized the complete code as below.
document.addEventListener('DOMContentLoaded', function(event) {
const tabHeaders = document.getElementsByClassName('tab-headers')[0];
const tabContents = document.getElementsByClassName('tab-contents')[0];
Array.from(tabHeaders.children).forEach((targetHeader) => {
// Tab Headers: All Click Events
targetHeader.addEventListener('click', () => {
const targetName = targetHeader.dataset.target;
const colorClass = targetHeader.dataset.color;
const targetContent = document.getElementById(targetName);
// Set all to default setting
Array.from(tabHeaders.children).forEach((tabHeader) => {
tabHeader.classList.remove('active');
tabHeader.classList.remove(tabHeader.dataset.color);
tabHeader.classList.add('bg-gray-700');
tabHeader.firstElementChild.classList.remove('bg-white');
});
// Except the chosen one
targetHeader.classList.add('active');
targetHeader.classList.remove('bg-gray-700');
targetHeader.classList.add(colorClass);
targetHeader.firstElementChild.classList.add('bg-white');
// Showing the content
Array.from(tabContents.children).forEach((tabContent) => {
tabContent.style.display = 'none';
});
targetContent.style.display = 'block';
targetContent.classList.add(colorClass);
});
// Tab Headers: Mimic All Hover Events
targetHeader.addEventListener('mouseenter', () => {
const targetName = targetHeader.dataset.target;
const targetContent = document.getElementById(targetName);
targetContent.firstElementChild.classList.add('is-hovered');
});
targetHeader.addEventListener('mouseleave', () => {
const targetName = targetHeader.dataset.target;
const targetContent = document.getElementById(targetName);
targetContent.firstElementChild.classList.remove('is-hovered');
});
});
// Tab Headers: Default
tabHeaders.getElementsByClassName('active')[0].click();
});
You can see how the length of the javascripts hogging your screen. This is an issue. We should find a way to make this easier to be read.
What’s Next?
Yeah we will find a way, but first, let’s port the stylesheet to Tailwind CSS
.
Consider continue reading [ Tabs - NPM - Tailwind CSS ].