1

As the title states, I'm making a tabbed section to switch content upon click which works fine, how can I make it so upon clicking a new tab it has a smooth transition to the content as well as prevent jumping to the top of the page every time I click a tab?

I've tried adding the function which prevents it for links but this isn't a link so that doesn't seem to be working.

HTML

 <section class="featured-books">
        <div class="featured-books-title"><h2>Featured Books</h2></div>
        <ul class="tabs">
            <li data-tab-target="#featured" class="active tab">Featured</li>
            <li data-tab-target="#on-sale" class="tab">On Sale</li>
            <li data-tab-target="#most-viewed" class="tab">Most Viewed</li>
        </ul>
        <div id="featured" data-tab-content class="active">
            <div class="featured-tab">
                <img src="./images/12-rules.jpg">
                <img src="./images/7-habits.jpg">
                <img src="./images/art-of-war.jpg">
                <img src="./images/boundaries.jpg">
                <img src="./images/unlimited-memory.jpg">
                <img src="./images/meaning-of-marriage.jpg">
                <img src="./images/meditations.jpg">
                <img src="./images/peaceful-parents.jpg">
                <img src="./images/plant-paradox.jpg">
                <img src="./images/spirit-filled-life.jpg">
                <img src="./images/javascript-definitive-guide.jpg">
                <img src="./images/atomic-habits.jpg">
            </div>
        </div>
        <div id="on-sale" data-tab-content>
        </div>
        <div id="most-viewed" data-tab-content>
        </div>
    </section>

CSS

.featured-books h1 {
    display: flex;
    justify-content: center;
}

[data-tab-content] {
    display: none;
}
    
.active[data-tab-content] {
    display: block;
}
    
.tabs {
    display: flex;
    justify-content: center;
    list-style-type: none;
    margin: 0;
    padding-bottom: 60px;
    padding-top: 16px;
}


.tab {
    border-radius: 20px;
    cursor: pointer;
    padding: 10px;
}

.tab.active {
    background-color: #CCC;
}

.tab:hover {
    background-color: #aaa;
}



/**------FEATURED TAB CONTENT------*/

.featured-tab {
    position: absolute;
    justify-content: center;
    align-items: center;
    margin-top: 10px;
    width: 100vw;
    display: grid;
    grid-template-columns: repeat(auto-fill,minmax(300px,300px));
    column-gap: 3px;
    row-gap: 40px;
  }
  
  .featured-tab img {
    width: 180px;
    height: auto;
    object-fit: cover;
    object-position: center;
  } 

JavaScript

const tabContents = document.querySelectorAll('[data-tab-content]')
  
  tabs.forEach(tab => {
    tab.addEventListener('click', () => {
      const target = document.querySelector(tab.dataset.tabTarget)
      tabContents.forEach(tabContent => {
      tabContent.classList.remove('active')
    })
    tabs.forEach(tab => {
      tab.classList.remove('active')
    })
    tab.classList.add('active')
    target.classList.add('active')
  })
}) 
Ricky Diaz
  • 11
  • 3

1 Answers1

0

Here is a simple example using a opacity transition but you can use height, width or transform if you would like. I use aria-attributes to keep track of things like which article is open and if the information in the article should be picked up by screen readers. The two most important CSS classes are show and hide. These control the opacity and when the transition takes place. Show has a slight delay so it waits for the one being hidden to get out of the way. As far as the JavaScript.

  1. Select all the buttons that have popups.
  2. Create a event listener to handle the click.
  3. Select the controlled article and all the articles.
  4. Check if the controlled article is currently hidden.
  5. If it is hide all the artiles.
  6. Change all the buttons aria-expanded attributes to false.
  7. Set the aria-expanded attribute on the clicked button to true.
  8. Set aria-hidden class on the controlled article to false.
  9. Remove the hide class and add the show class to the controlled article.

const buttons = document.querySelectorAll("[aria-haspopup=true]")

const handleClick = (event) => {
  const controls = event.target.getAttribute("aria-controls"),
  controlled = document.getElementById(controls),
  articles = document.querySelectorAll("article");
  if (controlled.getAttribute("aria-hidden") === "true") {
    articles.forEach(article => {
      article.setAttribute("aria-hidden", "true");
      article.classList.add("hide");
      article.classList.remove("show");
    })
    buttons.forEach(button => button.setAttribute("aria-expanded", "false"))
    event.target.setAttribute("aria-expanded", "true");
    controlled.setAttribute("aria-hidden", "false");
    controlled.classList.remove("hide");
    controlled.classList.add("show");
  }
}

buttons.forEach(button => {
  button.addEventListener("click", handleClick);
})
ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
}

li {
  margin-right: 10px;
}

article {
  height: calc(100vh - 50px);
  width: 100vw;
  position: absolute;
  top: 50px;
  left: 0;
}

#feature {
  background-color: red;
}

#sale {
  background-color: green;
}

#view {
  background-color: blue;
}

.show {
  opacity: 1;
  transition: opacity .2s ease-in-out .2s;
}

.hide {
  opacity: 0;
  transition: opacity .2s ease-in-out;
}

button[aria-expanded=true] {
  background-color:  #cceeff;
}
<ul>
  <li>
    <button aria-haspopup="true" aria-expanded="true" aria-controls="feature">Featured</button>
  </li>
  <li>
    <button aria-haspopup="true" aria-expanded="false" aria-controls="sale">On Sale</button>
  </li>
  <li>
    <button aria-haspopup="true" aria-expanded="false" aria-controls="view">Most Viewed</button>
  </li>
</ul>
<article class="show" id="feature" aria-hidden="false">
  <h1>Featured</h1>
</article>
<article class="hide" id="sale" aria-hidden="true">
  <h1>On Sale</h1>
</article>
<article class="hide" id="view" aria-hidden="true">
  <h1>Most Viewed</h1>
</article>
KJEK-Code
  • 695
  • 1
  • 5
  • 10
  • Thank you, had to tweek some css to make it work with my project but overall this really helped. When I have enough rep ill +1 you buddy. – Ricky Diaz Feb 16 '22 at 11:20
  • My pleasure @RickyDiaz, glad I could help. Good luck and keep coding! For future reference +1 is used to mark the answer you think best answers some ones question. Marking an answer on your question correct lets everyone know you got the information you needed and you will be moving on. – KJEK-Code Feb 16 '22 at 14:50
  • Thanks for the tip! Also how would i be able to keep the selected tab/button highlighted when active? – Ricky Diaz Feb 17 '22 at 10:11
  • @RickyDiaz use `button[aria-expanded=true]` and change the CSS attribute you would like to use to highlight it. I have edited my answer to use a different background color. Since we already change the aria-expanded attribute in JavaScript to keep track of which section is open you just need to edit the attribute in CSS to change it based on weather the attribute it true or false. – KJEK-Code Feb 17 '22 at 15:15