Skip to main content

Creating a master checkbox in a header cell

The article instructs how to create a master checkbox for a column with checkboxes with the following behaviour:

  • when all cells in a column are checked, a master checkbox in a header becomes checked as well
  • checking/unchecking a master checkbox checks/unchecks all cells in a column

More about custom cell content you can find here.

Adding a checkbox to a table cell

We assume that we have data items with the checked field, where the boolean value is stored. You can use either an HTML checkbox or import Checkbox from @svar-ui/svelte-core library to render the column value. Use $props to access row and column data as well as Grid api.

Then we update row data by calling the update-cell action when the checkbox value is changed:

CheckboxCell
<script>
import { Checkbox } from "@svar-ui/svelte-core";

let { row, column, api } = $props();

function onChange(ev) {
const { value } = ev;

//execute update action
api.exec("update-cell", {
id: row.id,
column: column.id,
value,
});
}
</script>

<Checkbox value={row[col.id]} onchange={onChange} />

And finally we apply a checkbox component to a Grid column by using the cell property of a column element in the columns array:

<script>
import { Grid } from "@svar-ui/svelte-grid";
import { getData } from "../data";
import { CheckboxCell } from "../custom/CheckboxCell.svelte";

const data = getData();

const columns = [
{
id: "checked",
cell: CheckboxCell,
header: "", // master checkbox will be rendered here in the next step
width: 36,
}
];
</script>
<Grid {data} {columns} />

Adding a checkbox to a header cell

Ready-made components are added to the header/footer cells in the same way as to column cells. We use $props to access Grid api and the onaction property to send a custom callback event to Grid. The event is sent each time a master checkbox changes its state either from manual clicks or data changes (when all rows are checked or one of them gets unchecked):

HeaderCheckboxCell
<script>
import { Checkbox } from "@svar-ui/svelte-core";

let { api, onaction } = $props();

let value = $state(false);

api.getReactiveState().data.subscribe(data => onCellCheck(data));

function onCellCheck(data) {
if (!data) ({ data } = api.getState());
const checked = data.every(d => d.checked === true);
// all rows are checked / unchecked
if (value !== checked) {
onaction &&
onaction({
action: "custom-header-check",
data: { value: checked },
});
value = checked;
}
}

function onChange(ev) {
const { value } = ev;
// manual click on a checkbox
onaction &&
onaction({
action: "custom-header-check",
// add eventSource to differentiate it from subscription to data
data: { value, eventSource:"click" },
});
}
</script>

<Checkbox bind:value onchange={onChange} />

Now you can import this component to Grid and apply it to a header cell by adding its name as the value of the cell parameter of the header element in the columns array. To handle clicks on a master checkbox, you need to handle the custom event it sends.

When the header checkbox is clicked, the action function is invoked with the argument "header-checkbox", which then triggers the checkHeader function. In the checkHeader function, the state of all checkboxes in the column is updated based on the value of the header checkbox.

<script>
import { Grid } from "@svar-ui/svelte-grid";
import { getData } from "../data";
import CheckboxCell from "../custom/CheckboxCell.svelte";
import HeaderCheckboxCell from "../custom/HeaderCheckboxCell.svelte";

let { data } = $state(getData());
let api = $state();

const columns = [
{
id: "checked",
cell: CheckboxCell,
header: [{ cell: HeaderCheckboxCell }], //master checkbox
width: 36,
},
];

// update all `checked` fields when header checkbox is clicked
function onHeaderCheck(ev) {
const { value, eventSource } = ev;
// ensure that the event source is "click"
// meaning it's a manual change (not from subscription to data)
if (eventSource == "click") {
data = api.getState().data.map(d => {
d.checked = value;
return d;
});
}
}
</script>

<Grid
{data}
{columns}
oncustomheadercheck={ev => onHeaderCheck(ev)} // Handle clicks on master checkbox
/>

Related articles: Adding custom content to cells