Opens in a new tab
27th Oct '22
/
1 comment

A CSS approach to content switcher in Bricks

A CSS approach to content switcher in Bricks

In this tutorial, we’ll build a 100% CSS solution for content toggles in Bricks.

Introduction

If you are looking for an integrated solution in Bricks to switch visibility between different elements – such as pricing tables or features – with a simple toggle, look no further and purchase BricksExtras. But if you’re willing to get your hands dirty and dive into custom CSS, then this tutorial might be useful!

The DOM structure

First of all, recreate the following DOM structure and assign the classes for each element as follow:

Note that the first element is a code block. The revealed-items can be any element.

Pure CSS method

The HTML

Paste the following HTML snippet in the code block:

<fieldset class="radio-switch">
  <!-- First Item -->
  <input type="radio" name="switch" id="item1">
  <label for="item1">Label 1</label>
  <!-- Second Item -->
  <input type="radio" name="switch" id="item2" checked>
  <label for="item2">Label 2</label>
  <!-- Third Item -->
  <input type="radio" name="switch" id="item3">
  <label for="item3">Label 3</label>
  <div class="highlight"></div>
</fieldset>

Feel free to change the label as per your needs, but don’t modify the attributes or it will break our animation.

In our example, we used 3 different labels/input but the CSS snippet supports up to 4 natively. To adjust that number to your needs, just delete/add more items as per your need.

The second label is the default active label on load because it has the attribute checked at the end of the input tag. Feel free to position it on any item of your choice.

The CSS

Paste the following CSS code to your page:

/* CSS Variables */
fieldset.radio-switch {
   --switch-item-number: 3;
   --switch-padding: 5px;
   --switch-bg: #fff;
   --switch-border-width: 1px;
   --switch-border-color: #ccc;
   --switch-border-radius: 50px;
   --switch-label-padding: 1.5rem 0.5rem;
   --switch-inactive-text-color: #666;
   --switch-active-text-color: #fff;
   --switch-active-bg-color: #350792;
}

/* Fieldset*/
fieldset.radio-switch {
   display: flex;
   position: relative;
   padding: 0;
   outline: 0;
   border: var(--switch-border-width) solid var(--switch-border-color);
   background-color: var(--switch-bg);
   border-radius: var(--switch-border-radius);
   overflow: hidden;
   width: 100%;
}

/* Hide Imputs*/
fieldset.radio-switch input {
   visibility: hidden;
   opacity: 0;
   display: none !important;
}

/* Labels */
fieldset.radio-switch label {
   z-index: 1;
   margin: 0;
   padding: var(--switch-label-padding);
   border-radius: var(--switch-border-radius);
   cursor: pointer;
   color: var(--switch-inactive-text-color);
   font-size: 14px;
   line-height: 1.4em;
   font-weight: 600;
}

/* Active Labels*/
fieldset.radio-switch input:checked+label {
   color: var(--switch-active-text-color);
   cursor: default;
}

/* Highlight */
fieldset.radio-switch label,
fieldset.radio-switch .highlight {
   width: calc(100% / var(--switch-item-number));
   display: flex;
   align-items: center;
   justify-content: center;
   text-align: center;
   transition: 300ms transform ease-in-out,
      300ms color ease-in-out;
}

fieldset.radio-switch .highlight {
   position: absolute;
   background-color: var(--switch-active-bg-color);
   top: calc(var(--switch-padding) / 2);
   left: calc(var(--switch-padding) / 2);
   bottom: 0;
   right: 0;
   border-radius: var(--switch-border-radius);
   height: calc(100% - var(--switch-padding));
   width: calc((100% / var(--switch-item-number)) - calc(var(--switch-padding) / var(--switch-item-number)));
}

/* Moving Highliht*/
fieldset.radio-switch input:nth-of-type(2):checked~.highlight {
   transform: translateX(100%);
}

fieldset.radio-switch input:nth-of-type(3):checked~.highlight {
   transform: translateX(200%);
}

fieldset.radio-switch input:nth-of-type(4):checked~.highlight {
   transform: translateX(300%);
}

/* Revealed Items */
body.bricks-is-frontend .revealed-items {
   display: none !important;
}

/* Active Reveald Item */
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(1):checked)~.revealed-items.item1,
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(2):checked)~.revealed-items.item2,
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(3):checked)~.revealed-items.item3,
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(4):checked)~.revealed-items.item4 {
   display: flex !important;
   animation: 300ms activeItems ease-in-out;
}


/* Custom Entrance Animation */
@keyframes activeItems {
   0% {
      transform: translateY(40px);
      opacity: 0;
   }

   100% {
      transform: translateY(0);
      opacity: 1;
   }
}

Note that the first section is a set of useful CSS variables so you can easily style the toggle as you need. The first variable –switch-item-number is mandatory and represents the number of labels inside your toggle. Since we used 3 different labels, we put 3 inside the variable. If you add or remove items from the HTML markup, update the correct number inside this variable as well.

Stack the switcher on mobile (optional)

If you’d like to vertically stack the switcher on mobile, add the following CSS code:

@media screen and (max-width: 767px) {
   fieldset.radio-switch {
      --switch-border-radius: 15px;
      flex-direction: column;
   }

   /* Highlight */
   fieldset.radio-switch .highlight,
   fieldset.radio-switch label {
      width: calc(100% - var(--switch-padding));
      height: calc((100% / var(--switch-item-number)) - calc(var(--switch-padding) / var(--switch-item-number)));
   }

   /* Moving Highliht*/
   fieldset.radio-switch input:nth-of-type(2):checked~.highlight {
      transform: translateY(100%);
   }

   fieldset.radio-switch input:nth-of-type(3):checked~.highlight {
      transform: translateY(200%);
   }

   fieldset.radio-switch input:nth-of-type(4):checked~.highlight {
      transform: translateY(300%);
   }
}

Firefox compatibility

Unfortunately, Firefox doesn’t support the :has() pseudo-element. To make it compatible, we need to apply some changes.

First of all, add an active class to the visible revealed item you want to show on load:

Then modify the CSS code as follow:

/* Active Reveald Item */
/*
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(1):checked)~.revealed-items.item1,
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(2):checked)~.revealed-items.item2,
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(3):checked)~.revealed-items.item3,
body.bricks-is-frontend .switcher-wrapper:has(input:nth-of-type(4):checked)~.revealed-items.item4 {
   display: flex !important;
   animation: 300ms activeItems ease-in-out;
}*/

body.bricks-is-frontend .revealed-items.active{
  display: flex !important;
  animation: 300ms activeItems ease-in-out;
}

Ultimately, add the following JavaScript script to your page:

// Load the script when the DOM is loaded
window.addEventListener('DOMContentLoaded', () => {

   // Query all the switchers on the page
   const radioGroups = document.querySelectorAll('.switcher-wrapper');

   // stop the script if there is no switcher
   if (radioGroups.length < 1) return;

   // Function to get all the siblings of an element
   const getSiblings = (elem) => {
      return Array.prototype.filter.call(elem.parentNode.children, (sibling) => {
         return sibling !== elem;
      });
   };

   // Loop in each switcher groups
   radioGroups.forEach((radioGroup) => {

      // Query the inputs
      const radios = radioGroup.querySelectorAll('input');

      // Query the revealed items
      const revealedItems = getSiblings(radioGroup);

      // Loop into each radio groups
      radios.forEach((radio, index) => {

         // Listener on click
         radio.addEventListener('click', () => {

            // Get the revealed item
            const revealedItem = revealedItems[index];

            // Remove the active class on all revealed items
            revealedItems.forEach(el => el.classList.remove('active'));

            // Add the active class to the active revealed item
            revealedItem.classList.add('active');
         })

      })

   })

})

Conclusion

If you set everything correctly, you should see a similar result on frontend:

Note that this solution is not accessible out of the box. If accessibility is mandatory for your project, consider using another solution or be prepared to add some extra work!

Get access to all 633 Bricks code tutorials with BricksLabs Pro

1 comment

Leave your comment

 

Related Tutorials..

How to display a Query Loop in 3 columns in Bricks

How to display a Query Loop in 3 columns in Bricks

This tutorial provides the builder settings and CSS codes that can be pasted in order to create a 3-columns query loop container inside Bricks Builder.
Categories:
How to Create a Right Overflow Effect on Sliders in Bricks

How to Create a Right Overflow Effect on Sliders in Bricks

In this tutorial, we'll learn how to recreate a nice overflow effect on the right of our sliders in Bricks. Introduction Recently, I've been asked…
Categories:
Pro
Sticky Scrolling in Bricks Builder

Sticky Scrolling in Bricks Builder

Updated on 22 Apr 2024 This Pro tutorial provides the steps to fix elements in the viewport i.e., make them sticky while adjacent content in the section…
Categories:
Tags:
Sticky Element using Position Sticky

Sticky Element using Position Sticky

If you are looking to make an element, typically, the site header sticky whether it is at the top of the page to begin with…
Categories:
Tags:
Pro
Dynamic Horizontal Posts Accordion in Bricks

Dynamic Horizontal Posts Accordion in Bricks

Creating a horizontal accordion of featured images from posts output by Bricks' query loop.
Categories:
Tags:
Pro
CSS Grid for Posts Element in Bricks

CSS Grid for Posts Element in Bricks

The "Posts" element in Bricks has "Grid" as the default layout but the actual CSS it applies on the page feels hacky with negative margins…
Categories:
Add masonry style to the Remote Template list

Add masonry style to the Remote Template list

This article will show you how to transform the remote templates list of Bricks in a masonry style without cropping your images - it will…
Categories:
Tags:
Width and Height of Mobile Hamburger Toggle in Bricks

Width and Height of Mobile Hamburger Toggle in Bricks

Looking to change the size of Bricks hamburger toggle in the mobile menu? The default width value of 20px can be changed by selecting the…
Categories:
How to Add a Dot Separator Between Nav Menu Items in Bricks

How to Add a Dot Separator Between Nav Menu Items in Bricks

Looking to add a circular dot separator between the nav menu items in your Bricks site? Add the following at Bricks → Settings → Custom…
Categories:
Tags: