SuperDuper Checkboxes With Table
by Bruno G.
HTML
<table class="checkbox-grid">
<thead>
<tr>
<th class="row-header"><button type="button" class="btnAll">All</button></th>
<th class="col-header">Option 1</th>
<th class="col-header">Option 2</th>
<th class="col-header">Option 3</th>
<th class="col-header">Option 4</th>
<th class="col-header">Option 5</th>
</tr>
</thead>
<tbody>
<tr>
<td class="row-header">Label 1</td>
<td><label for="r1c1"><input type="checkbox" id="r1c1"></label></td>
<td><label for="r1c2"><input type="checkbox" id="r1c2"></label></td>
<td><label for="r1c3"><input type="checkbox" id="r1c3"></label></td>
<td><label for="r1c4"><input type="checkbox" id="r1c4"></label></td>
<td><label for="r1c5"><input type="checkbox" id="r1c5"></label></td>
</tr>
<tr>
<td class="row-header">Label 2</td>
<td><label for="r2c1"><input type="checkbox" id="r2c1"></label></td>
<td><label for="r2c2"><input type="checkbox" id="r2c2"></label></td>
<td><label for="r2c3"><input type="checkbox" id="r2c3"></label></td>
<td><label for="r2c4"><input type="checkbox" id="r2c4"></label></td>
<td><label for="r2c5"><input type="checkbox" id="r2c5"></label></td>
</tr>
<tr>
<td class="row-header">Label 3</td>
<td><label for="r3c1"><input type="checkbox" id="r3c1"></label></td>
<td><label for="r3c2"><input type="checkbox" id="r3c2"></label></td>
<td><label for="r3c3"><input type="checkbox" id="r3c3"></label></td>
<td><label for="r3c4"><input type="checkbox" id="r3c4"></label></td>
<td><label for="r3c5"><input type="checkbox" id="r3c5"></label></td>
</tr>
</tbody>
</table>
<table class="checkbox-grid">
<thead>
<tr>
<th class="row-header"></th>
...
CSS
.checkbox-grid .checked {
background-color: #007bff;
color: white;
}
JavaScript
(function ($) {
$.fn.checkboxGrid = function () {
return this.each(function () {
const $table = $(this);
let lastChecked = null;
// Handle checkbox click with Shift key for range selection
$table.on('click', 'input[type=checkbox]', function (event) {
const $checkboxes = $table.find('tbody input[type=checkbox]');
if (lastChecked && event.shiftKey) {
const start = $checkboxes.index(lastChecked);
const end = $checkboxes.index(this);
const min = Math.min(start, end);
const max = Math.max(start, end);
const checkState = lastChecked.checked;
$checkboxes.slice(min, max + 1).prop('checked', checkState);
}
lastChecked = this;
});
// Handle row toggle
$table.on('click', 'tbody th.row-header', function () {
const $row = $(this).closest('tr');
const $rowCheckboxes = $row.find('input[type=checkbox]');
const checkState = $rowCheckboxes.first().prop('checked');
$rowCheckboxes.prop('checked', !checkState);
});
// Handle column toggle
$table.on('click', 'thead th.col-header', function () {
const colIndex = $(this).index();
const $colCheckboxes = $table.find(`tbody tr td:nth-child(${colIndex + 1}) input[type=checkbox]`);
const checkState = $colCheckboxes.first().prop('checked');
$colCheckboxes.prop('checked', !checkState);
});
// Handle Ctrl-A to toggle all checkboxes
$(document).on('keydown', function (event) {
if (event.ctrlKey && event.key.toLowerCase() === 'a') {
event.preventDefault();
const $upperLeftCheckbox = $table.find('tbody tr:nth-child(2)...