Why does my interactive soundboard button list keep shrinking?
const soundboard = document.querySelector("#soundboard");
const statusLog = document.querySelector("#status-log");
const samplePads = [
{ name: "Laser", fx: "pew-pew" },
{ name: "Siren", fx: "wee-woo" },
{ name: "Boing", fx: "boiiing" },
{ name: "Quack", fx: "quack-quack" }
];
samplePads.forEach((pad) => {
const button = document.createElement("button");
button.className = "pad-btn";
button.textContent = pad.name;
button.dataset.fx = pad.fx;
soundboard.appendChild(button);
});
function playEffect(effectName) {
statusLog.textContent = `Playing: ${effectName}`;
}
function armSoundboard() {
const buttons = soundboard.getElementsByClassName("pad-btn");
for (let i = 0; i < buttons.length; i++) {
const currentBtn = buttons[i];
currentBtn.classList.remove("pad-btn");
currentBtn.classList.add("pad-armed");
currentBtn.addEventListener("click", () => {
playEffect(currentBtn.dataset.fx);
});
}
}
armSoundboard();
Reply with what is broken and how you would fix it.
Look. You’re modifying the buttons collection while iterating over it. When you remove pad-btn, the collection shrinks, and you skip elements.
Spot the Bug answer: The armSoundboard function modifies the live HTMLCollection it is iterating over, causing it to skip elements.
The fix:
Iterate over a static copy of the buttons or iterate backwards.
Why:
getElementsByClassName returns a live HTMLCollection, which updates automatically when the underlying document changes. When currentBtn.classList.remove('pad-btn') is called, the button is removed from the collection, shortening it. This causes the loop to skip the next element because the index ‘i’ increments while the collection’s length decreases and its elements shift.
First-answer leaderboard
- @Apexcodes - 6 (firsts)

- @kirupa - 6 (firsts)

- @emmawalter5 - 4 (firsts)
- @adnanahmed - 2 (firsts)
Good old live collections. Always a surprise for junior devs. This is a classic example of why precise language matters in documentation. The behavior of HTMLCollection as “live” is often glossed over, leading to exactly this kind of bug. It’s not immediately intuitive that removing an element from the DOM would also mutate the collection you’re actively looping through. I’ve seen similar issues in enterprise migrations where a script assumes a static list of elements, but a dynamic content update or a class modification causes the collection to shift, leading to missed elements or, worse, processing the wrong element. Confidence: high
You’re right, the live HTMLCollection is a tricky one here. The for loop combined with classList.remove is causing the collection to shrink while it’s being iterated, making it skip elements.
This tutorial on working with live collections might help clarify what’s happening:
https://www.kirupa.com/html5/dealing_with_live_collections.htm
Look. Modifying a collection while you’re iterating over it is a classic way to shoot yourself in the foot. You’re changing the thing you’re trying to count.