Gillian
Gillian

Reputation: 287

How do I get an element to re-set Attribute value when clicking self as well as when clicking other buttons?

I have some vanilla JavaScript that listens for a click and when there is a click, four things happen:

  1. a 'form-opened' class is added to the button
  2. the 'aria-expanded' attribute is set to 'true'
  3. a previously hidden div is displayed.
  4. the 'after' text of the button changes to 'Close info' (this is controlled with CSS based on whether the button contains the new class of 'form-opened'.)

When another button is clicked, the reverse happens to the first-clicked button with the added class being removed, the 'aria-expanded' attribute is re-set to 'false', the div is hidden again (again set with CSS) and the 'after' text reverts to 'Read more'.

BUT, if the same button is clicked a second time, whilst the added class is removed as expected, and the div is hidden again, the 'aria-expanded' attribute is not re-set to 'false'. Can anyone explain why and tell me what I should be doing, please? (No jQuery, thanks).

const tips = Array.from(document.querySelectorAll('.toggle-button'));
tips.forEach((tip) => {
    tip.addEventListener('click', () => {
        tips
        .filter((f) => f !== tip)
        .forEach((f) => {
        f.setAttribute('aria-expanded', false);
        f.classList.remove('form-opened');
        });
        tip.setAttribute('aria-expanded', true);
        tip.classList.contains('form-opened');
        tip.classList.toggle('form-opened');
    });
});
.toggle-button ~ .tips {
  display: none;
}
button.toggle-button[aria-expanded="false"]:after {
  content: "Read more";
}
.toggle-button.form-opened ~ .tips {
  display: block;
  margin-bottom: 16px;
}
button.toggle-button[aria-expanded="true"]:after {
  content: "Close info";
  cursor: pointer;
}
.visually-hidden {
  border: 0;
  padding: 0;
  margin: 0;
  position: absolute;
  height: 1px;
  width: 1px;
  overflow: hidden;
  white-space: nowrap;
  display: inline-block;
}
<div class="toggle-box">
<label for="button-1" class="visually-hidden toggle-list">Open or Close info</label><button id="button-1" class="toggle-button" aria-expanded="false"></button>
<div class="tips">
  Here is some text that is to be revealed </div>
</div>
<div class="toggle-box">
<label for="button-2" class="visually-hidden toggle-list">Open or Close info</label><button id="button-2" class="toggle-button" aria-expanded="false"></button>
<div class="tips">
  Here is some text that is to be revealed </div>
</div>
<div class="toggle-box">
<label for="button-3" class="visually-hidden toggle-list">Open or Close info</label><button id="button-3" class="toggle-button" aria-expanded="false"></button>
<div class="tips">
  Here is some text that is to be revealed </div>
</div>

I have seen some similar queries, but not quite the same or very old or they use jQuery.

Upvotes: 0

Views: 617

Answers (1)

elldur
elldur

Reputation: 2103

Clicking a button only sets all other button's aria-expanded attributes to false. You also have to toggle the state of the current button:

const tips = Array.from(document.querySelectorAll('.toggle-button'));
tips.forEach((tip) => {
    tip.addEventListener('click', () => {
        tips
            .filter((f) => f !== tip)
            .forEach((f) => {
                f.setAttribute('aria-expanded', false);
                f.classList.remove('form-opened');
            });
        
        // Toggle both aria-expanded attribute and form-opened class
        tip.setAttribute(
            "aria-expanded",
            tip.getAttribute("aria-expanded") == 'true' ? 'false' : 'true'
        );
        tip.classList.toggle('form-opened');
    });
});

Upvotes: 2

Related Questions