Last active
July 17, 2025 22:07
-
-
Save jameskerr/9305bc7ba469d2be66fcef644a3c6b16 to your computer and use it in GitHub Desktop.
Mutli Select Stimulus Controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Base from "controllers/base"; | |
export default class extends Base { | |
static targets = ["checkbox", "toggler", "count", "menu", "hide"]; | |
mount() { | |
this.on("turbo:morph", document, this.update); | |
this.on("click", this.togglerTarget, this.toggle); | |
} | |
update() { | |
const allBoxes = this.checkboxTargets; | |
const allCount = allBoxes.length; | |
const checkedBoxes = allBoxes.filter((box) => box.checked); | |
const checkedCount = checkedBoxes.length; | |
if (checkedCount == 0) { | |
this.closeMenu(); | |
this.togglerTarget.checked = false; | |
this.selectAllButton.innerHTML = "Select All"; | |
} else if (checkedCount == allCount) { | |
this.openMenu(); | |
this.togglerTarget.checked = true; | |
this.selectAllButton.innerHTML = "Deselect All"; | |
} else { | |
this.togglerTarget.checked = false; | |
this.selectAllButton.innerHTML = "Select All"; | |
this.openMenu(); | |
} | |
this.selectedCount = checkedCount; | |
} | |
selectAll() { | |
for (const checkbox of this.checkboxTargets) checkbox.checked = true; | |
this.update(); | |
} | |
toggle() { | |
if (this.allChecked) this.clear(); | |
else this.selectAll(); | |
} | |
clear() { | |
for (const checkbox of this.checkboxTargets) checkbox.checked = false; | |
this.update(); | |
} | |
get allChecked() { | |
return this.checkboxTargets.every((box) => box.checked); | |
} | |
get selectAllButton() { | |
return this.togglerTarget; | |
} | |
set selectedCount(count) { | |
this.countTarget.innerHTML = count; | |
} | |
openMenu() { | |
this.menuTarget.removeAttribute("hidden"); | |
this.hideTargets.forEach((el) => { | |
el.setAttribute("hidden", true); | |
}); | |
} | |
closeMenu() { | |
this.menuTarget.setAttribute("hidden", true); | |
this.hideTargets.forEach((el) => { | |
el.removeAttribute("hidden"); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Each checkbox gets the "checkbox" target.
The "select all" checkbox is the "toggler" target.
The "menu" target contains the bulk actions.
The "hide" targets are any other elements you want hidden when the menu is open.
I use this to replace the normal toolbar with the bulk menu.
I also like to setup my event listeners in my controller sometimes. That's what that "on" function is for. It's defined in the Base. The base controller looks like this.