A Content-switching Component Built 3 Ways: jQuery, JS, CSS

Share this article

Not too long ago, a friend of mine had constructed a UI component to change a page’s content based on the the current selection of a <select> element. Her code worked, but being new to JavaScript, she had built the component in jQuery and had asked me to help optimize it.

While not replicating the code exactly, I’ve created the following example to showcase the type of UI component she was trying to create:

<div class="select-area">
  <select name="choose" id="choose" class="input-select">
    <option value="nul" selected>Make a Selection</option>
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    <option value="opt3">Option 3</option>
  </select>
</div>

<section class="jqueryOptions opt1">
  <div class="content">
    <h2>Option 1 Content</h2>
    <p>
      ...
    </p>
  </div>
</section>

<section class="jqueryOptions opt2">
  <div class="content">
    <h2>Option 2 Content</h2>
    <p>
      ...
    </p>
  </div>
</section>

<section class="jqueryOptions opt3">
  <div class="content">
    <h2>Option 3 Content</h2>
    <p>
      ...
    </p>
  </div>
</section>

After optimizing it a bit, here is the jQuery we ended up using to toggle the display state of the selected content block.

$(function() {
  $('.jqueryOptions').hide();

  $('#choose').change(function() {
    $('.jqueryOptions').slideUp();
    $('.jqueryOptions').removeClass('current-opt');
    $("." + $(this).val()).slideDown();
    $("." + $(this).val()).addClass('current-opt');
  });
});

So what’s going on here?

The above jQuery function looks for all the content blocks that have a class of ‘jqueryOptions’ and hides them by default.

Then when a user changes the selected option of the select input (which has an ID of ‘choose’), the function closes any potentially open content blocks using jQuery’s .slideUp() method and then opens the selected option with slideDown(). It does this by taking the value of the selected option (referenced as this) and referencing the element with the class name that matches the value in “this”.

So:

<option value="opt1">Option 1</option>

Matches:

<section class="options opt1">
  ...
</section>

And here’s a demo:

See the Pen Content switching component with jQuery by SitePoint (@SitePoint) on CodePen.

Or see the working full page demo here.

That wasn’t too hard, huh?

So why not leave it at that?

The problem with the jQuery solution is that we were including jQuery (98kb compressed) for just this small bit of functionality. We could do better.

Without changing the markup, let’s take a look at how we can create the same sort of effect first using vanilla JavaScript and then using only CSS.

First, let’s think about what needs to happen to recreate this effect.

  • The content needs to be hidden by default.
  • Upon making a selection, we need to show the chosen content.
  • We need to also hide any previously open content when a new option is selected.

There are some additional pieces to this that will be explained in the code, but those are the three main points of this script we need to keep in mind. One of which, hiding the content by default, we can set by default with CSS, so that’s one crossed off. Two to go.

Creating a Vanilla JavaScript Version

To start, let’s set up a few variables to make our life easier.

var selectInput = document.getElementById('choose'),
    panels = document.querySelectorAll('.options'),
    currentSelect,
    i;

Now we have variables to easily access our input select (selectInput), the different content panels (panels), a placeholder for a current selection, and an iterator.

Next we need to write some functions to help us take care of the items from the above bulleted list.

Starting with the last bullet first, we need to make sure that any content that was in view gets hidden when a new option is selected. For that we’ll create its own function:

function clearShow() {
  for ( i = 0; i < panels.length; i++ ) {
    panels[i].classList.remove('show');
  }
}

The clearShow() function is doing a couple of things. First, it’s taking our panels variable (which is a list of all nodes on the page with a class of “options”) and it iterates over each (three in this case) and removes the class of “show” from all of them.

The “show” class is what makes the content visible on our page.

Now that we have a way to remove the “show” class from each content block, we need a way to add “show” to the selected panel.

function addShow(showThis) {
  var el = document.getElementsByClassName(showThis);
  for ( i = 0; i < el.length; i++ ) {
     el[i].classList.add('show');
   }
}

The addShow() function receives an argument called showThis and adds the “show” class to the panel node that has a class that matches the current value of the select input. Now we still need one more piece to pass the showThis value to addShow().

function vUpdate() {
  currentSelect = selectInput.value;

  clearShow();
  addShow(currentSelect);
}

selectInput.addEventListener('change', vUpdate);

The vUpdate() function executes whenever the select input is updated (detected via the change event). So when vUpdate() runs, it does the following:

  • Grabs the current value of selectInput and stores it in the currentSelect variable.
  • Executes the clearShow function to remove any traces of .show from the panels.
  • Executes the addShow() function, passing in currentSelect to complete the missing piece of that function
  • Assigns .show to the panel with the class that matches the current value of the select input.

You can check out the demo below to see it all in action:

See the Pen Content switching component with vanilla JavaScript by SitePoint (@SitePoint) on CodePen.

Or you can check out the full page demo here.

But before we move on… If you chose an option from the select input and then refresh the page, the value of the input may stay but the appropriate panel isn’t shown.

We can fix that by adding the following:

if (selectInput.value !== 'nul') {
  currentSelect = selectInput.value;
  addShow(currentSelect);
}

This if construct will check to see if the selectInput value is something other than nul. If that’s the case, it will pass in the value of the current selection to the addShow() function, firing that on page reload. Handy to fix the rare case where the page was refreshed and the select element displayed a value, but the appropriate content wasn’t shown.

And finally, in the instance that you need to support Internet Explorer 9 or lower, we can’t use classList(). To work around this, here are functions to add and remove classes from an element. The above CodePen demos are using these functions:

function addClass(elm, newClass) {
    elm.className += ' ' + newClass;
}

function removeClass(elm, deleteClass) {
  elm.className = elm.className.replace(new RegExp("\\b" + deleteClass + "\\b", 'g'), '').trim();
  /* the RegExp here makes sure that only
     the class we want to delete, and not
     any other potentially matching strings 
     get deleted.
  */
}

Can it be done with only CSS?

With a lot of components I make, I like to try to see how closely I can come to replicating them in a pure CSS solution. However, where the jQuery and vanilla JavaScript solutions could be based on the same markup, the CSS-only solution needs to be modified.

The biggest, and most important, change from the previous versions is that the select needed to be completely replaced. Where the previous examples were relying on the value of the select element to change which content panel would be shown, CSS alone isn’t aware of these value changes and thus can’t utilize the different values to toggle different selector chains.

The select element will just have to be recreated, and to do that, we’ll use what is known as the ‘check box / radio button hack’.

Here’s the markup for our new ‘select element’.

<input type='checkbox' class="invis" id="open_close" />
<input type='radio' name='opts' class="invis" id="opt1" />
<input type='radio' name='opts' class="invis" id="opt2" />
<input type='radio' name='opts' class="invis" id="opt3" />

<header class="header-base">
  <div class="content">
    <p>
      Choose an Option
    </p>

    <div class="select-area">
      <label for="open_close" class="input-select">
        ...
      </label>

      <ul class="select-options">
        <li>
          <label for="opt1">Option 1</label>
        </li>
        <li>
          <label for="opt2">Option 2</label>
        </li>
        <li>
          <label for="opt3">Option 3</label>
        </li>
      </ul>
    </div>

  </div>
</header>

What’s been done here is basically a recreation of a select element as best as HTML and CSS can allow without any help from JavaScript. The inputs above the header act as the controls for the styling anchors for the select and content panels on the site. And the new unordered list and labels becomes our new select element.

The labels for opt1, opt2, and opt3 change the checked state of the radio buttons with the corresponding IDs. In the CSS, depending on which radio button is selected, the corresponding panel is set to display using the general sibling selector.

#opt1:checked ~ main .opt1,
#opt2:checked ~ main .opt2,
#opt3:checked ~ main .opt3 {
  display: block;
  height: 100%;
  overflow: visible;
  visibility: visible;
}

There are a bunch of little details to replicate the select element that are reliant on the appropriate radio button being checked and CSS’s general sibling selector. For more information on the general sibling selector and other neat things you can do with only CSS, you should check out my articles You Can Do That With CSS? and CSS Morphing Menu.

What I don’t cover in those articles are some of the tougher aspects of recreating the select element.

It’s pretty straightforward that we want to have the content of the page immediately updated based on which option is pressed. The problem we run into is that if the select element and the content blocks were all based on the same radio buttons, clicking on the select element would make the content disappear. Not only that, but if the select options were opened, and we clicked on one of those, the options would then disappear and the content block would show up.

To mitigate this UX flaw, I added the <input type="checkbox" class="invis" id="open_close" />. Now the select element and current content could be open at the same time. The downside here is that the select element doesn’t close when an option is clicked, but instead only closes when clicked again. Not ideal. However, I felt it was a better experience than the one I mentioned previously. To help draw attention to the select element needing to be clicked again to close, I changed the down arrow to an X when the element is opened:

#open_close:checked ~ .header-base .select-area .select-options {
  opacity: 1;
  visibility: visible;
}

#open_close:checked ~ .header-base .select-area:after {
  border: none;
  content: 'X';
  top: -24px;
}

An additional feature of true select elements I wanted to recreate was that when a new option is selected, the main select element’s text changes to that option. Using the :before pseudo-element, that text can change based on which radio button is selected:

.input-select:before {
  content: 'Make a Selection';
}

#opt1:checked ~ .header-base .input-select:before {
  content: 'Option 1';
}

#opt2:checked ~ .header-base .input-select:before {
  content: 'Option 2';
}

#opt3:checked ~ .header-base .input-select:before {
  content: 'Option 3';
}

You can see the above, and more, in action by viewing the source code of the CSS-only CodePen demo:

See the Pen Content switching component with pure CSS by SitePoint (@SitePoint) on CodePen.

And here is the full page version.

In conclusion, a short summary of the pros and cons…

We just considered three different ways to create a similar interface using jQuery, then using vanilla JavaScript, and then again using just CSS. Each technique has its own pros and cons.

The jQuery solution is by far the easiest to implement, having very little code.

The downside to the jQuery solution is that if you only need the library for this one interface, you’re adding an entire library for a single purpose.

The Vanilla JavaScript solution, utilizing CSS transforms and transitions is a very close replication to the jQuery solution. Minified it clocks in at 486 bytes – obviously much smaller than the jQuery alternative.

The downside to this solution is that some of the JavaScript used is not supported in all browsers, and to support those browsers, you’ll need to write additional work-around functions (as I’ve done).

The CSS only solution is great for those looking to experiment with CSS or for those that aren’t familiar enough with JavaScript. However, it requires quite a bit of repetitious, markup-reliant CSS to get it to work properly, and can have a negative impact on a site’s accessibility, since you have to use elements in ways they weren’t meant to be used.

Regardless of which solution you gravitate towards, be sure to weigh the pros and cons of each and aim to offer the best user experience.

Frequently Asked Questions (FAQs) about Content Switching Components

What is a content switching component and how does it work?

A content switching component is a dynamic element in web development that allows for the interchange of content within a single space on a webpage. It works by using JavaScript or other programming languages to manipulate the Document Object Model (DOM), replacing one set of content with another based on user interaction or predefined conditions. This can be particularly useful for creating interactive user interfaces, where space is limited but multiple sets of information need to be displayed.

How can I replace spaces with dashes in JavaScript?

In JavaScript, you can use the replace() method to replace spaces with dashes. Here’s a simple example:
let str = "This is a test";
let newStr = str.replace(/ /g, "-");
console.log(newStr); // Outputs: This-is-a-test
In this code, “/ /g” is a regular expression that matches all spaces in the string, and “-” is the replacement for each match.

How can I make all letters lower case in JavaScript?

JavaScript provides the toLowerCase() method for this purpose. Here’s how you can use it:
let str = "This Is A Test";
let lowerCaseStr = str.toLowerCase();
console.log(lowerCaseStr); // Outputs: this is a test
This code converts all the characters in the string to lower case.

What are some content swap tools for link building?

There are several tools available for content swapping in link building, including SEO plugins for WordPress like Yoast SEO and All in One SEO Pack. These tools can help you optimize your content for search engines, making it easier for others to find and link to your content.

Can I swap a website yet keep its high ranking for a competitive keyword?

Yes, it’s possible to swap a website and maintain its high ranking for a competitive keyword, but it requires careful planning and execution. You’ll need to ensure that the new website is optimized for the same keyword and that it provides high-quality, relevant content. It’s also important to set up proper redirects from the old website to the new one to preserve link equity.

How can I replace all occurrences of a string in JavaScript?

JavaScript provides the replaceAll() method for this purpose. Here’s how you can use it:
let str = "This is a test. This is only a test.";
let newStr = str.replaceAll("test", "trial");
console.log(newStr); // Outputs: This is a trial. This is only a trial.
This code replaces all occurrences of the word “test” with the word “trial”.

Scott O`HaraScott O`Hara
View Author

Scott O'Hara is a UX designer & developer based out of Boston Massachusetts. He loves pushing the limits of CSS, designing for everyone, writing about what he knows & what he's learning and developing wonderful product experiences.

css selectjQueryLouisL
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week