skip to Main Content

I using this script to show/hide content. However, how can I close open elements when opening one?
I tried with something like this, but it’s not working correctly:

// Get siblings
var contentSiblings = document.querySelectorAll('.content');

// close them before opening new one
if (contentSiblings) {
        contentSiblings.forEach((elem) => {
                if (elem.classList.contains('is-visible')) {
                        hide(elem);
                }
        });
}
// Show/hide filter content
var show = function (elem) {
    elem.classList.add('is-visible');
};

// Hide an element
var hide = function (elem) {
    elem.classList.remove('is-visible');
};

// Toggle element visibility
var toggle = function (elem) {

    // If the element is visible, hide it
    if (elem.classList.contains('is-visible')) {
        hide(elem);
        return;
    }

    // Otherwise, show it
    show(elem);
};

// Listen for click events
document.addEventListener('click', function (event) {

    // Make sure clicked element is our toggle
    if (!event.target.classList.contains('btn')) return;

    // Prevent default link behavior
    event.preventDefault();

    // Get the selected content
    var content = document.querySelector(event.target.hash);
    if (!content) return;

    // Toggle the content
    toggle(content);

}, false);
.content {
    display: none;
    opacity: 0;
    transition: opacity .15s linear;
}

.content.is-visible {
    display: block;
    opacity: 1;
}
<a class="btn" id="btn-one" href="#one">Button one</a>
<a class="btn" id="btn-two" href="#two">Button two</a>
<div class="content" id="one">Content one</div>
<div class="content" id="two">Content two</div>

3

Answers


  1. Probably a simple approach would just be to always hide all "content" elements before showing one. For example, the show function can first hide all elements and then show the specified element:

    // Show/hide filter content
    var show = function (elem) {
        // Hide all others first
        document.querySelectorAll('.content').forEach(hide);
    
        elem.classList.add('is-visible');
    };
    
    // Hide an element
    var hide = function (elem) {
        elem.classList.remove('is-visible');
    };
    
    // Toggle element visibility
    var toggle = function (elem) {
    
        // If the element is visible, hide it
        if (elem.classList.contains('is-visible')) {
            hide(elem);
            return;
        }
    
        // Otherwise, show it
        show(elem);
    };
    
    // Listen for click events
    document.addEventListener('click', function (event) {
    
        // Make sure clicked element is our toggle
        if (!event.target.classList.contains('btn')) return;
    
        // Prevent default link behavior
        event.preventDefault();
    
        // Get the selected content
        var content = document.querySelector(event.target.hash);
        if (!content) return;
    
        // Toggle the content
        toggle(content);
    
    }, false);
    .content {
        display: none;
        opacity: 0;
        transition: opacity .15s linear;
    }
    
    .content.is-visible {
        display: block;
        opacity: 1;
    }
    <a class="btn" id="btn-one" href="#one">Button one</a>
    <a class="btn" id="btn-two" href="#two">Button two</a>
    <div class="content" id="one">Content one</div>
    <div class="content" id="two">Content two</div>
    Login or Signup to reply.
  2. You can add a function hideAllElements to hide all visible elements before show content:

    // Show/hide filter content
    function show(elem) {
        hideAllElements()
        
        elem.classList.add('is-visible');
    };
    
    // Hide an element
    function hide (elem) {
        elem.classList.remove('is-visible');
    };
    
    // Hide all elements
    function hideAllElements (elem) {
        const visibleElements = document.querySelectorAll('.is-visible');
        for (const element of visibleElements) {
            element.classList.remove('is-visible');
        }
    };
    
    // Toggle element visibility
    function toggle (elem) {
    
        // If the element is visible, hide it
        if (elem.classList.contains('is-visible')) {
            hide(elem);
            return;
        }
    
        // Otherwise, show it
        show(elem);
    };
    
    // Listen for click events
    document.addEventListener('click', function (event) {
        
        // Make sure clicked element is our toggle
        if (!event.target.classList.contains('btn')) return;
    
        // Prevent default link behavior
        event.preventDefault();
    
        // Get the selected content
        const content = document.querySelector(event.target.hash);
        if (!content) return;
    
        // Toggle the content
        toggle(content);
    
    }, false);
    .content {
        display: none;
        opacity: 0;
        transition: opacity .15s linear;
    }
    
    .content.is-visible {
        display: block;
        opacity: 1;
    }
    <a class="btn" id="btn-one" href="#one">Button one</a>
    <a class="btn" id="btn-two" href="#two">Button two</a>
    <div class="content" id="one">Content one</div>
    <div class="content" id="two">Content two</div>

    On a side note, if you give descriptive names to your functions, the comments are not needed anymore.

    Login or Signup to reply.
  3. you can also do:

    document.body.addEventListener('click', e =>
      {
      if (!e.target.matches('.btn')) return;
      
      if ( document.body.className === e.target.id )
        document.body.className = '';
      else  
        document.body.className = e.target.id;
      })
    .content {
      display: none;
      opacity: 0;
      transition: opacity .15s linear;
    }
    
    body.btn-one #one.content ,
    body.btn-two #two.content { 
      display: block;
      opacity: 1;
      }
    <a class="btn" id="btn-one" href="#">Button one</a>
    <a class="btn" id="btn-two" href="#">Button two</a>
    <div class="content" id="one">Content one</div>
    <div class="content" id="two">Content two</div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search