StimulusJS checkboxes. Select all. Deselect all
With StimulusJS it’s easy to add Select all
, Deselect all
:
# terminal
rails g stimulus checkbox-select-all
2025 Update - covers edge cases, interim state #
export default class extends Controller {
static targets = ["parent", "child"];
connect() {
this.childTargets.map((x) => (x.checked = false));
if (this.hasParentTarget) {
this.parentTarget.checked = false;
}
}
toggleChildren() {
if (this.parentTarget.checked) {
this.childTargets.map((x) => (x.checked = true));
} else {
this.childTargets.map((x) => (x.checked = false));
}
}
toggleParent() {
let checkedStatuses = this.childTargets.map((x) => x.checked);
if (checkedStatuses.includes(true) && checkedStatuses.includes(false)) {
this.parentTarget.indeterminate = true;
this.parentTarget.checked = false;
} else if (checkedStatuses.includes(true)) {
this.parentTarget.checked = true;
this.parentTarget.indeterminate = false;
} else {
this.parentTarget.checked = false;
this.parentTarget.indeterminate = false;
}
}
childTargetConnected() {
if (this.hasParentTarget) {
this.toggleParent();
}
}
childTargetDisconnected() {
if (this.hasParentTarget) {
this.toggleParent();
}
}
checkAll() {
this.childTargets.map((x) => (x.checked = true));
if (this.hasParentTarget) {
this.parentTarget.checked = true;
this.parentTarget.indeterminate = false;
}
}
uncheckAll() {
this.checkAll();
if (this.hasParentTarget) {
this.parentTarget.click();
}
}
}
Old JS #
import { Controller } from "@hotwired/stimulus";
// Connects to data-controller="checkbox-select-parent"
export default class extends Controller {
static targets = ["parent", "child"];
connect() {
// set all to false on page refresh
this.childTargets.map((x) => (x.checked = false));
this.parentTarget.checked = false;
}
toggleChildren() {
if (this.parentTarget.checked) {
this.childTargets.map((x) => (x.checked = true));
// this.childTargets.forEach((child) => {
// child.checked = true
// })
} else {
this.childTargets.map((x) => (x.checked = false));
}
}
toggleParent() {
if (this.childTargets.map((x) => x.checked).includes(false)) {
this.parentTarget.checked = false;
} else {
this.parentTarget.checked = true;
}
}
}
In the HTML:
- initialize the stimulus controller
data-controller="checkbox-select-all"
around all the checkboxes - “Select all” should have
data-checkbox-select-all-target="parent"
data-action="change->checkbox-select-all#toggleChildren"
- Each other checkbox should have
data-checkbox-select-all-target="child"
data-action="change->checkbox-select-all#toggleParent"
- BEWARE: each checkbox should have it’s unique
id
,name
,value
<!-- html -->
<div data-controller="checkbox-select-all">
<input
type="checkbox"
id="all"
name="all"
value="all"
data-checkbox-select-all-target="parent"
data-action="change->checkbox-select-all#toggleChildren"
/>
<label for="all"> Select all</label><br />
<input
type="checkbox"
id="vehicle1"
name="vehicle1"
value="Bike"
data-checkbox-select-all-target="child"
data-action="change->checkbox-select-all#toggleParent"
/>
<label for="vehicle1"> I have a bike</label><br />
<input
type="checkbox"
id="vehicle2"
name="vehicle2"
value="Car"
data-checkbox-select-all-target="child"
data-action="change->checkbox-select-all#toggleParent"
/>
<label for="vehicle2"> I have a car</label><br />
<input
type="checkbox"
id="vehicle3"
name="vehicle3"
value="Boat"
data-checkbox-select-all-target="child"
data-action="change->checkbox-select-all#toggleParent"
/>
<label for="vehicle3"> I have a boat</label><br /><br />
</div>
That will work.
Here’s how you can do the same using rails check_box_tag
:
+<div data-controller="checkbox-select-all">
+ <%= label_tag "select all" %>
+ <%= check_box_tag "select all", nil, nil, { data: { checkbox_select_all_target: "parent", action: "change->checkbox-select-all#toggleChildren" } } %>
<%= form_with url: bulk_update_users_path, method: :patch, id: :bulk_actions_form do |form| %>
<%= form.submit "active" %>
<%= form.submit "disabled" %>
<% end %>
<%= render partial: "user", collection: @users %>
+</div>
+<%= check_box_tag "user_ids[]", user.id, nil, { data: { checkbox_select_all_target: "child", action: "change->checkbox-select-all#toggleParent" }, multiple: true, form: :bulk_actions_form } %>
That’s it!
Did you like this article? Did it save you some time?