Instructor: In this video we're gonna implement
a very popular component which is a tabbed component.
And you will see tabbed components
on many websites these days.
So it's great to learn how to build one yourself.
So the component that we're gonna build
in this video is this one.
Now a tabbed component can appear in many different ways,
but what they all have in common
is that they have some kind of tabs like this here.
And when you clicked it up
then the content of this area below will change.
And so that's exactly what happens here with these buttons.
So basically these three are our tabs.
And then as we click on one of the tabs,
it will reveal the associated content.
So a little bit like tabs here in our browser, right?
So each browser tab has its own webpage.
And so here each tab has its own content area, basically.
So I'm sure you've seen this on other websites
and so let's now go ahead and implement this ourselves.
Okay, now for this component,
we actually need a bunch of HTML.
So let's first take a look at that.
So the whole tabbed component
in our case is called operations.
So let's scroll down here also.
And so this section here is about the operations
we can do on a bank account
and therefore this component here is called operations.
And you can also see that here on the page.
Then we have a the tab container basically.
So that's this element.
And so you can also see it here again
and it's the element which will contain the three tabs.
And so each tab is itself a button
and it has this class of operations tab, okay?
Then below that we have the content.
And in fact, we have three contents.
So we have one content element here for each of the tabs.
All right, so the first one here as you see
is called operations-content-1
then the other one is operations-content-2
and operations-content-3.
So as we click on one of these tabs,
we will not create any new content.
What we will do instead is to hide the other tabs basically.
So you see that right now this first one here
has the operations content active class.
And so therefore this one is visible
and all the others are hidden.
And what's also important here is that
these buttons here, they have this data tab attribute.
And so this one is number one
and this will then be associated with this class name here.
So operations content and then again one
but more about that in a minute
when we actually implement this ourselves.
So for now we just need to get down
the basic structure of the HTML here.
And it might be a good idea for you to pause the video
and take a minute or two to get yourself familiar
with this HTML structure
and all of the class names that are involved here, okay?
And you can even take a look at the CSS
because there's also a lot of CSS involved here, all right?
So of course I couldn't write all of this code here
together with you now, because that would take way too long.
All right, but anyway
let's not build this tabbed component here.
And we're gonna start by selecting the tabs, okay?
And that will keep the elements here open
so we can see it at all time.
And so you'll see that the buttons
they have the class operations tab.
So tabs=documents.querySelectorAll
and then with the class operations_tab.
Then let's also select the tabs container
and so that is this element here.
Let's actually go ahead and copy it.
And finally, also the three content areas.
So that's here, operations content.
You see I cannot copy it for some reason.
It doesn't matter.
So a tabs content is document.querySelectorAll.
So because again, we have three of them.
All right, so we have our selections nicely done
and now we can actually work on the functionality
and let's start by adding event handlers
to these buttons here, right?
Because that is the action that we actually want to handle
in this component.
So we could do it like this.
So taking all the tabs and then on each of them
we could attach an event handler.
So for example, like this.
So for each, because we want to do it on each of them,
so we get then each tab and then tab.addEventListener click.
And let's just use a quick arrow function here
because this is really just a demonstration.
Well, nothing happens.
Let's try to reload this page.
Yeah indeed, now we get the tab locked to the console.
Now, however, as we already learned in the last video
doing this here is a bad practice
because what if we had like 200 tabs?
Then we would have 200 copies
of this exact callback function here
and that would simply slow down the page.
So that's not at all desirable.
And so let's get rid of this
and one more time, use events delegation.
And remember that for event delegation,
we need to attach the event handler
on the common parent element
of all the elements that we're interested in.
And in our case, that is this tabs container, right?
So we have our buttons here.
So right here or buttons
and a common parent of all of them
is this tab container that we already selected previously.
And so let's attach our event handler
to that element instead.
So tabsContainer.AddEventListener, click,
we need the event of course,
so that we can figure out where the click happened.
And so let's now actually work on
or matching strategy, okay?
So we already know that we are interested in the buttons.
And so let's now figure out which button was clicked.
So let's actually create an element called clicked
that we can then use to work with.
And so what about this?
So what about simply using the e.target?
Well, let's see.
So in our console, let's now click somewhere here
and indeed now we got the button that was clicked, okay?
However, there is a problem
when we click here on this number.
So you see that now we did not get a button
but we got this spin element.
And that's because inside of this button,
we actually have another element.
And so now, even though
it looked like we clicked on the button here
or here for example,
actually we are clicking on this span element, right?
So we are not actually clicking on the button,
but we still need the button.
So no matter if we click on this button itself
or here on the span element
we actually need the button element itself
because from that button
we will need to read this data tab attribute here
because as I mentioned earlier,
this one contains the number of the tab
that should become visible.
And so here this data attribute
becomes really important to store information in the DOM.
So basically we need a way of finding the button element
whenever we click on this span element, right?
Now, one simple way to fix it,
which would not really fix it actually
is to do some DOM traversing
and simply select the parent element.
We can move up the DOM tree
and instead of simply taking a e.target
we can use the parent element of that.
So let's see what happens then.
And so now indeed when we click on the number,
we get the button.
And so again that's because that is the parent element
of that span.
Now the problem appears
when we click on the button itself,
because now of course we will also get the parent
of the button element.
And so that is this container.
But of course that is not what we want.
So basically what we want is to get the button,
no matter if we click here on the span
or on the button itself.
So we need a way of selecting the parent element
that is always a tab.
And can you think of a special method
that we learned previously to do that?
Well, the solution is right here in the previous video.
Well, and that's down here somewhere.
So remember that we want a way of going upwards,
but we want to specify that we want to select
an operations tab.
And so we can use this closest method for exactly that.
So remember that I said
that this method is gonna be really helpful
in event delegation.
And so now that's actually the case.
Okay, so this method makes it really easy for us
to dynamically get the element
that we're interested in.
So here, instead of always selecting the parent element
we will search basically for the closest operations tab.
And so here we need to do the exact same query as that.
All right, and this should actually now fix our problem.
So let's see, when we click the button itself
then we get the button
and when we click the number here so the span,
then we also get the button
because now it finds the closest parent
with this class name,
which indeed is the button itself, so the tab
And here we get to tab number two
as you can see down here.
And here we get tab number three, great.
And let's actually immediately do something
with this select the tab.
So the tab that is currently active here
has a different style as you can see.
So it's a bit moved up.
And so that's because the active tab
basically has this class.
So where's that?
It has this clap of operations tab active.
All right, so we can simply add that
to the element that was just clicked.
So classList.add operations_tab_active, okay?
And now as we click
you see that it activates basically does tab.
Now of course later
then all the other tabs we'll have to move down
but we're gonna take care of that in a second.
Because now watch what happens when we actually click
on the tabs container itself.
So outside of any of the buttons
but still in the tabs container
where this EventListener is actually attached to.
So you see that we get null here
and that's because null is the results
of the closest method here
when there is no matching parent element to be found.
So of course, when we click here in this tabs container
then there is gonna be no parent with this class.
And so therefore, as I just said, we get to null.
And so we need to fix that now in our code
and basically ignore any clicks that happen on that area.
So basically ignore any clicks
where the result is then null, all right?
So we can do that by saying,
if there is no clicked, then return immediately.
And this is something that we haven't done before.
So what I'm doing here is called a guard clause.
So it's basically an if statement
which will return early if some condition is matched.
So in this case, when there's nothing clicked
then we want to immediately finish this function.
And in this case, when we have null which is a faulty value,
then not faulty will become true
and then the function will return
and none of the code that's after it will be executed.
But of course, if clicked does exist
then this return will not be executed
and the rest of the code will be executed just fine.
So this is a more modern way of writing this.
So we could have written instead also,
if there is a clicked on element, then do this.
And this is the more traditional way
as we have been doing it all the time.
But this is actually more modern
because it looks a bit nicer
because we don't need to create all these additional blocks.
So in this case, just this block
but sometimes when we have so many conditions
it can become a little bit confusing.
And then it's a bit cleaner
to simply return the function immediately
if a certain condition is matched.
And again in this case,
whenever there is no clicked element here
then we want to simply return to function right away.
And so then that code here will not be executed
but otherwise, of course it will be executed.
And so that's null see what happens.
So now clicking outside, nothing happens.
Of course, we still get to the null here
but no error occurs
because null JavaScript is no longer trying to execute
this line of code here, okay?
But now let's actually take care
of basically putting all of these other buttons down
as I was saying.
So when I click one of them,
then the other ones show to move down.
So basically we should remove this class from them, right?
And so the solution to that
is before we add this class here to anyone,
we will simply remove it on all of the tabs.
So we removed them on all.
So that's all the tabs.forEach.
And so each tab I'm simply calling T here.
And then tab.clasList.remove.
And so now that should work,
and yeah, it does, okay?
So this is something that we do quite usually.
So basically clearing the class on all of them
and then only add it afterwards on one of them.
So that's at a comment here, active tab.
But now finally let's actually
activate the content area itself
because that's the main part
that we're actually interested in.
Now remember that the information about
which content area should be displayed
is here in this data attribute.
So let me click again.
And so in this case, we want the tab a number two.
And so that's this number two is encoded here
basically in this data attribute.
So having the number two here
means that we want to select the element
which has the class of operations_content_2, okay?
So let's do that.
Let me grab this here.
So the selector,
and then let's select it.
So document.querySelector.
And now I'm using a template string here,
because of course we don't want to hard code
the number two here
but instead we want to get that
exactly from the data attribute that I just told you.
So let me just show that again to you.
Now we got an error here
but just put something there for now.
So it is called data tab, okay.
And so remember all these attributes
are in the element and then in the dataset property.
So the element that was clicked
is indeed stored in or variable clicked, right?
So every time we click a button,
that button is then stored in the clicked variable
and then .data set.tab.
So that's only the part after the data.
Remember, so it's just tab.
So in this case, it's gonna be two.
And so we already have that now selected
and then we want to add a special class to it.
So that's classList.add
and let's just check out the class that we need to add.
So we can see that here on the first content area
which is already active.
And so the class here is operations content active.
Okay, and one more time you can check out the CSS
to figure out why actually this makes the element active.
And we can quickly do that ourselves.
So here it is actually the active, right?
And so basically what this does
is to change the display property
to something which is not none.
So previously without this active part,
so just operation content makes it display none
which basically hides it.
But then as it becomes active, we give it display grid
and then specify all of these properties down, all right?
So this would actually already been working
just to really see it as a bit better in the console also.
Let's lock this value also to the console, okay?
But let's see.
And indeed it now appeared down here.
Great, so it's no longer hidden.
And indeed we successfully read that value here
from the data tab, which is two.
And the same, it's going to happen here for three.
And so you'll see that's the content number three
also appeared down here.
Now of course this is not quite finished yet
because we want the other ones to be hidden.
So that's the whole idea of this component.
And so basically all we need to do
is to do the same that we did for the tabs.
So basically removing the active class for all of them
before then adding it
to the one that we're interested in, all right?
So basically just what we have here.
So let's select all the contents
and that we actually already have here, right?
So tabs content is also a note list
because of query selector all
that we can now loop over
and then remove that active class from all of them.
So tabsContent.forEach
and I'm just calling it C very short here.
So C for content.
So class list remove.
And so you'll see that it's always the same idea.
So it's all about removing and adding classes
to manipulate the page to look just like we want, all right?
So this comment is actually more here.
So activate tab and here
remove the act of classes for both the tab
and the content areas.
And with this actually our component
should already be working.
So let's see.
And yeah, beautiful, it works great, all right.
Let's just get rid
of all these different console.logs here
because we only need them for development,
but now we're done.
So let's just quickly recap.
And as I just mentioned a minute ago
the whole idea when we build components like this
is to just add and remove classes
as necessary to manipulate the content to our needs.
That's actually the exact same thing
we did with a modal window.
So if you take a look at the code, it's a bit similar.
So to hide and display the modal window
all we do is to add and remove this hidden class.
Now, in this case, it's a little bit more complex
but the idea is always the same.
It's to work with classes
that have some styles for showing and hiding the classes.
And so if you're not yet really familiar with CSS,
it's also important that you really check out to CSS
to build these components for yourself
and the same goes for the HTML.
But of course, I could not write this code here as well
because then this tutorial would take
like one hour instead of 15 minutes.
But anyway, I hope that this was fun
and that make sure to understand what we did here
including the HTML and CSS.
And then let's go right to the next video.