CSS/JS : A tab control using the :target pseudo class

Words
677
Reading
4 min
Listen
Play
4y

I'm working on a little electron.js project at the moment. I did not do any web development for a long time and have a lot of new things to learn. Here's a little report of my last experiment.

Context

I wanted to implement a kind of tab functionality in my application. I searched the web and found an elegant solution (imho) based on the ":target" pseudo class. As I had a long break from this project, I forgot my source... But it was something like this : https://www.sitepoint.com/css3-tabs-using-target-selector/

Here's is the current layout :

The behaviour is simple and well known : clicking on the little snippet at left top of the window switches the tab.

Note that I haven't worked on the UI yet (so it's basic and awful at the moment!!)

Code

HTML

The HTML code is basic:

<div class="tabs">
  <div id="patientTab">
    <a id="patientTabLink" href="#patientTab">Patients</a>
      <div>The Patient Tab</div>
  </div>
  <div id="patientFileTab">
    <a href="#patientFileTab">Medical file</a>
    <div>The Patient medical file</div>
  </div>
  <div id="appointmentsTab">
    <a href="#appointmentsTab">Appointments</a>
    <div>The Appointments Tab</div>
  </div>
</div>

There is a div container named "tabs". Inside we find 3 tabs : Patient, Patient File, and Appointments.

The tab selector is an anchor, and the tab content goes into another div. The anchor references the div you want to show.

CSS

div.tabs {
  min-height: 7em;
  position: relative;
  line-height: 1;
  z-index: 0;
  height: calc(100% - var(--tabs-top-margin)) ;
  margin-top: var(--tabs-top-margin); 
}

div.tabs :target {
  outline: none;
}

div.tabs > div:target > a {
  border-bottom: 0.1em solid;
  background: rgb(224, 224, 224);
}

div.tabs > div {
  display: inline;
}

div.tabs > div > a {
  color: black;
  background: #CCC;
  padding: 0.2em;
  border: 0.1em outset;
  border-bottom: 0.1em solid;
  border-radius: 5px 5px 0px 0px;
  text-decoration: none;
  margin-right: -4px;
}

div.tabs > div:target > div {
  position: absolute;
  z-index: -1;
}

div.tabs > div:not(:target) > div {
  position: absolute;
  z-index: -3;
}

div.tabs > div > div {
  background: #CCC;
  left: 0;
  top: 1.3em;
  bottom: 0;
  right: 0;
  overflow: auto;
  padding: 0.3em;
  border: 0.1em outset ;
}

I won't dive into the details of each CSS definition. The trick here is to use the z-index property. The div.tabs > div:not(:target) > div is the default value, as you did not click a link yet, and sets the z-index at -3.

When you click on one of the tab selector, you activate the link. This activation sets the ":target" pseudo class on the div element.
The div.tabs > div:target > div takes over and set the z-index at -1, showing the right tab.

Set the "primary" tab

The first problem was that the last div was shown first.
I added this code to "force" a primary tab.

div.tabs > div#patientTab  > div{
  z-index: -2;
}

-2 is between ":target" (-1) and "not(:target)" (-3), giving a kind of priority to the tab of my choosing.

The reset problem

The second problem I met was that I could not find a way to reset the ":target" pseudo class easily.
When one chooses another patient, I want to display the first tab. But when I changed the content of the page, the focus stayed on the last selected tab.

I first choose this pure CSS solution to have the less javascript possible, but I finally came to the conclusion that javascript would be necessary in order to have some kind of control on the displayed tab.

I tried several things using JQuery, but I was unable to remove the ":target" pseudo class.

I was left with 2 possibilities :

  • completely reload the page
  • manage to simulate a click on the desired link

I chose the second solution with this very simple jQuery code :

function resetTarget(){
  $('#patientTabLink')[0].click();
}

I struggled at first with the click() function not working but finally found a stackoverflow comment explaining that I needed to add the [0] in order to access to the DOM element, and not just the jQuery object. This gets the job done !

You can call the resetTarget() function where needed in your code when you want to reset the :target pseudo class.

That's it. I hope that this little trick will be helpful to some of you !

CSS/JS : A tab control using the :target pseudo class | Ecency