I'm using the w3schools how-to on tabs. (https://www.w3schools.com/howto/howto_js_tabs.asp) I noticed that their example does not allow for tabs to be untoggled and hide the text when pressed again. Can someone briefly explain how I would be able to integrate that into my code if I'm following theirs? Thanks.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {font-family: Arial;}
/* Style the tab */
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons inside the tab */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 17px;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
</style>
</head>
<body>
<h2>Tabs</h2>
<p>Click on the buttons inside the tabbed menu:</p>
<div class="tab">
<button class="tablinks" onclick="openCity(event, 'London')">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<div id="London" class="tabcontent">
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
<script>
function openCity(evt, cityName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
</script>
</body>
</html>
Not sure if I understand correctly, but what you describe is not the "expected" behaviour of a tabbed interface. Why would you want content to be hidden? In a tabbed interface (think navigation), there is usually always one tab active, showing it's content, so clicking the active tab should simply do nothing and not hide the content (at least in conventional tabbed interfaces). Maybe you are looking more for an accordion-like behaviour?
In other words, the behaviour of the (notoriously crappy) example from W3Schools is not how a tabbed interface is supposed to work, when initialized, no content is shown, the user needs to click a tab first to see something, that's not good UX... the first tab should already be active!
But if you really want to go for this behaviour, it could be done like this:
function openCity(evt, cityName) {
// Declare all variables
var i, tabcontent, tablinks;
if ( evt.currentTarget.classList.contains('active') ) {
document.getElementById(cityName).style.display = "none";
evt.currentTarget.classList.remove('active');
} else {
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
}
/* Style the tab */
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
<!-- Tab links -->
<div class="tab">
<button class="tablinks" onclick="openCity(event, 'London')">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<!-- Tab content -->
<div id="London" class="tabcontent">
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
There are different approaches that you could take. You could use if else statements to check whether an element in the for loops contains a specific CSS style or class name so in this case active. Then you may disable it by changing its style through JS when the condition is met.
Related
I'm using this method from W3schools for tabbed content and it's working well except for one minor detail that is overlooked in their example. When the tab is closed by clicking on the X in the content, the tab remains in the active presentation, a darker color in this instance. I want the tabs to revert to their original appearance when the X is clicked (i.e. the lighter color). I contacted W3schools to point out their example is missing this feature but did not hear back. Can someone enlighten me on the code needed to achieve this?
function openCity(evt, cityName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
body {font-family: Arial;}
/* Style the tab */
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons inside the tab */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 17px;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
/* Style the close button */
.topright {
float: right;
cursor: pointer;
font-size: 28px;
}
.topright:hover {color: red;}
<body>
<h2>Tabs</h2>
<p>Click on the x button in the top right corner to close the current tab:</p>
<div class="tab">
<button class="tablinks" onclick="openCity(event, 'London')" id="defaultOpen">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<div id="London" class="tabcontent">
<span onclick="this.parentElement.style.display='none'" class="topright">×</span>
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<span onclick="this.parentElement.style.display='none'" class="topright">×</span>
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<span onclick="this.parentElement.style.display='none'" class="topright">×</span>
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
</body>
Try add this to your script:
document.querySelectorAll('.topright').forEach(item => {
item.addEventListener('click', event => {
let elems = document.querySelectorAll(".tablinks");
[].forEach.call(elems, el => {
el.classList.remove("active");
});
});
});
Removing active class for tabLinks will do..
function openCity(evt, cityName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
function closeCity(evt){
let tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
evt.target.parentElement.style.display="none";
}
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
body {font-family: Arial;}
/* Style the tab */
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons inside the tab */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 17px;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
/* Style the close button */
.topright {
float: right;
cursor: pointer;
font-size: 28px;
}
.topright:hover {color: red;}
<h2>Tabs</h2>
<p>Click on the x button in the top right corner to close the current tab:</p>
<div class="tab">
<button class="tablinks" onclick="openCity(event, 'London')" id="defaultOpen">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<div id="London" class="tabcontent">
<span onclick="closeCity(event)" class="topright">×</span>
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<span onclick="closeCity(event)" class="topright">×</span>
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<span onclick="closeCity(event)" class="topright">×</span>
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
I'm trying to refactor this w3schools for a toggleable tabs code because all of us know that using inline JavaScript is a very bad practice so I'm trying to sepearte them as much as possible so I selected the tablinks and I added an event listener but I'm struggling with the city names (take a look to their code and you'll understand what I'm talking about)
any help please and thank you in advance
HTML
<!-- Tab links -->
<div class="tab">
<button class="tablinks" onclick="openCity(event, 'London')">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<!-- Tab content -->
<div id="London" class="tabcontent">
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
CSS
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
JavaScript
function openCity(evt, cityName) {
// Declare all variables
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
w3schools is a very good source of bad practice, because they often take many shortcuts while trying to highlight the one small example they are giving.
In practice, you would solve this situation by using a data- attribute. If you don't recognize some of the calls, please refer to some of these articles:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
https://developer.mozilla.org/en-US/docs/Glossary/IIFE
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
// Wrap our code in an IIFE in order to avoid polluting the global namespace
// and to facilitate faster garbage collection
(function(){
// Preload queries for later use
const tabs = document.querySelectorAll('.tablinks');
const content = document.querySelectorAll('.tabcontent');
// iterate tab to create content interaction
tabs.forEach(f => // f will be the tab element in this loop
// Assign click event to each tab
f.addEventListener('click',function(){
// Locate any previously marked active tab element
const prevActive = document.querySelector('.tablinks.active');
// If a previously marked element exists set its classname to default
if(prevActive) prevActive.className = 'tablinks';
// Assign the currently clicked tab element the active class
f.className = 'tablinks active';
// Iterate through the content to look for the data-attribute we used earlier
content.forEach(c => { // c will be the content element in this loop
// if the id of the element matches the data attribute from the tab then show the content
c.style.display = c.id == f.getAttribute("data-city") ? "block" : "none" ;
})
})
);
})();
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
<div class="tab">
<button class="tablinks" data-city="London">London</button>
<button class="tablinks" data-city="Paris">Paris</button>
<button class="tablinks" data-city="Tokyo">Tokyo</button>
</div>
<!-- Tab content -->
<div id="London" class="tabcontent">
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
<button id="London" class="tablinks">London</button>
var btns = document.querySelectorAll('.tab button')
btns.forEach((btn)=>{
btn.addEventListener('click', (event)=>{
openCity(event, btn.id, btn)
})
})
Give each button an id with the city name, then pass the id to the openCity function
You can pass the btn to your openCity function too
I am trying to use tablinks in my program using the w3school article
how to js tabs
CSS
function openCity(evt, cityName) {
// Declare all variables
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
/* Style the tab */
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
<!-- Tab links -->
<div class="tab">
<button class="tablinks" onclick="openCity(event, 'London')">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<!-- Tab content -->
<div id="London" class="tabcontent">
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
Below is the code to make one tab as "Active" one.
<button class="tablinks" onclick="openCity(event, 'London')" id="defaultOpen">London</button>
<script>
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
</script>
When i click on one tab i need to make it as default, so that next time when i open the page, the latest page should be the default.
I have few pages like sales, costs,expenses etc.
When the user makes an entry in costs, it will redirect to another jsp page and inserts the record to db and then redirect back to the home.jsp page where we have all these tabs. So when we redirect it should open the costs tab as default.
forgive me if my english is rude or badly formatted . english is not my mother tongue .
Thank you very much.. any help will be highly appreciated.
Based on the article you linked, looks like css is governing which tab is showing.
This excerpt is from their example page later on.
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
So if you want to manage which tab and page is active, you will need to manage that active class using Javascript just like they are doing with the function on their example page.
Using their example, i was able to change the tab that displays by just calling:
document.getElementById("Tokyo").style.display = "block";
var tokyo = document.getElementsByClassName("tablinks")
tokyo[2].className += " active";
I'v tried to create this w3 code on a page works fine. But when I want to add it more then one (f.e. two or three tabs), the tabs doesn't work. What must I change in the script if i click the first tab of the second tab section; it doesn't want to open it in the first tab section.
The second I would like to know just styling it:
if I config the css that the tabcontent would be auto height, the tabs on the left side auto adjust to it (I tried to set all of them to auto height but both side auto heighted oneself different).
The code is that:
function openCity(evt, cityName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
* {box-sizing: border-box}
body {font-family: "Lato", sans-serif;}
/* Style the tab */
.tab {
float: left;
border: 1px solid #ccc;
background-color: #f1f1f1;
width: 30%;
height: 300px;
}
/* Style the buttons inside the tab */
.tab button {
display: block;
background-color: inherit;
color: black;
padding: 22px 16px;
width: 100%;
border: none;
outline: none;
text-align: left;
cursor: pointer;
transition: 0.3s;
font-size: 17px;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current "tab button" class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
float: left;
padding: 0px 12px;
border: 1px solid #ccc;
width: 70%;
border-left: none;
height: 300px;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>Click on the buttons inside the tabbed menu:</p>
<div class="tab">
<button class="tablinks" onclick="openCity(event, 'London')" id="defaultOpen">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<div id="London" class="tabcontent">
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
</body>
</html>
as you can see when the page reloads the section under these tabs are empty (maybe using wrong word) need to click this to see content
All I want is when page the loads content on the first tab show by default
Click Here
hope you undersatnd me
Do these 2 things to achieve the desired result:
1.
Use style="display:block;" on the first tab because the logic of your javascript code works like this.
So on page load the 1st tab content will alwyas be visible and on tab change it will work accordingly.
Add class="tablinks active" to the first tab link to make it active.
<!DOCTYPE html>
<html>
<head>
<style>
body {font-family: "Lato", sans-serif;}
/* Style the tab */
div.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons inside the tab */
div.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 17px;
}
/* Change background color of buttons on hover */
div.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
div.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
</style>
</head>
<body>
<p>Click on the buttons inside the tabbed menu:</p>
<div class="tab">
<button class="tablinks active" onclick="openCity(event, 'London')">London</button>
<button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
<button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>
<div id="London" class="tabcontent" style="display:block;">
<h3>London</h3>
<p>London is the capital city of England.</p>
</div>
<div id="Paris" class="tabcontent">
<h3>Paris</h3>
<p>Paris is the capital of France.</p>
</div>
<div id="Tokyo" class="tabcontent">
<h3>Tokyo</h3>
<p>Tokyo is the capital of Japan.</p>
</div>
<script>
function openCity(evt, cityName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}
</script>
</body>
</html>
All of your .tabcontent tabs have their display property set to none. Change the display property of your first tab to block and it will show by default.
You can use jquery for this and then put this in script
$('.tablinks').eq(0).click();
Working example