Examples › Records selection

In order to enable records selection, you’ll have to add the following properties to the DataTable:

  • selectedRecords → an array of currently selected records (with the same TS type as the records property);
  • onSelectedRecordsChange → a callback that will be invoked when the user alters the current selection.

When adding these two properties, the component will render a selection checkbox column and handle user input as following:

  • Clicking a row selection checkbox will result in selecting/deselecting the underlying record;
  • Clicking the column header checkbox will result in selecting/deselecting all visible records;
  • Shift-clicking a row selection checkbox will result in intuitively selecting all records between the last clicked record and the current one.
Name
Street address
City
State
Feest, Bogan and Herzog21716 Ratke DriveStromanportWY
Cummerata - Kuhlman6389 Dicki StreamSouth GateNH
Goyette Inc8873 Mertz RapidDorthysideID
Runte Inc2996 Ronny MountMcAllenMA
Goldner, Rohan and Lehner632 Broadway AvenueNorth LouieWY
Doyle, Hodkiewicz and O'Connell576 Joyce WaysTyraburghKS
Rau - O'Hara7508 Lansdowne RoadShieldsboroughMI
Tillman - Jacobi57918 Gwendolyn CirclesSheridanportMI
Connelly, Feest and Hodkiewicz7057 Stanley RoadKearaburghCA
Shanahan, Robel and Beier378 Berta CrescentWest GerryKS
Kling - McLaughlin8346 Kertzmann SquareSouth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
No records
const [selectedRecords, setSelectedRecords] = useState<Company[]>([]);

return (
  <>
    <DataTable
      striped
      highlightOnHover
      withTableBorder
      withColumnBorders
      records={companies}
      columns={columns}
      selectedRecords={selectedRecords}
      onSelectedRecordsChange={setSelectedRecords}
    />
    {/* delete button... */}
  </>
);

Disable selection of certain records

You can disable the selection of certain records by providing an `isRecordSelectable` property like so:

const [selectedRecords, setSelectedRecords] = useState<Company[]>([]);

return (
  <DataTable
    withTableBorder
    withColumnBorders
    records={companies}
    columns={columns}
    selectedRecords={selectedRecords}
    onSelectedRecordsChange={setSelectedRecords}
    isRecordSelectable={(record) => record.name.length < 14}
  />
);

The above code will result in the following behavior:

Name
Street address
City
State
Feest, Bogan and Herzog21716 Ratke DriveStromanportWY
Cummerata - Kuhlman6389 Dicki StreamSouth GateNH
Goyette Inc8873 Mertz RapidDorthysideID
Runte Inc2996 Ronny MountMcAllenMA
Goldner, Rohan and Lehner632 Broadway AvenueNorth LouieWY
Doyle, Hodkiewicz and O'Connell576 Joyce WaysTyraburghKS
Rau - O'Hara7508 Lansdowne RoadShieldsboroughMI
Tillman - Jacobi57918 Gwendolyn CirclesSheridanportMI
Connelly, Feest and Hodkiewicz7057 Stanley RoadKearaburghCA
Shanahan, Robel and Beier378 Berta CrescentWest GerryKS
Kling - McLaughlin8346 Kertzmann SquareSouth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
No records

Customizing the selection column className and style

By default, the selection column has an absolute width of 0, to that it only takes up the space required by the selection checkboxes. If you’re not happy with this behavior, or you have other reasons to customize the column’s properties, you can do so by providing the selectionColumnClassName and/or selectionColumnStyle properties:

const [selectedRecords, setSelectedRecords] = useState<Company[]>([]);

return (
  <DataTable
    // other props...
    selectionColumnStyle={{ minWidth: 100 }}
  />
);
Name
Street address
City
State
Feest, Bogan and Herzog21716 Ratke DriveStromanportWY
Cummerata - Kuhlman6389 Dicki StreamSouth GateNH
Goyette Inc8873 Mertz RapidDorthysideID
Runte Inc2996 Ronny MountMcAllenMA
Goldner, Rohan and Lehner632 Broadway AvenueNorth LouieWY
Doyle, Hodkiewicz and O'Connell576 Joyce WaysTyraburghKS
Rau - O'Hara7508 Lansdowne RoadShieldsboroughMI
Tillman - Jacobi57918 Gwendolyn CirclesSheridanportMI
Connelly, Feest and Hodkiewicz7057 Stanley RoadKearaburghCA
Shanahan, Robel and Beier378 Berta CrescentWest GerryKS
Kling - McLaughlin8346 Kertzmann SquareSouth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
No records

Additional selection checkbox props

You can pass additional props to the selection checkboxes by providing the following properties:

  • checkboxProps → an object of props that will be applied to all selection checkboxes (both the column header checkbox and the row selection checkboxes);
  • allRecordsSelectionCheckboxProps → an object of props that will be applied to the column header checkbox;
  • getRecordSelectionCheckboxProps → a function that receives the underlying record and record index and returns an object of props that will be applied to the row selection checkboxes.
const [selectedRecords, setSelectedRecords] = useState<Company[]>([]);

return (
  <DataTable
    // other props...
    selectionCheckboxProps={{ size: 'xs' }}
    allRecordsSelectionCheckboxProps={{ 'aria-label': 'Select all records' }}
    getRecordSelectionCheckboxProps={(record) => ({ 'aria-label': `Select ${record.name}` })}
  />
);

In this example, the checkboxes will be rendered with a smaller size and will have custom aria-label attributes that will be read by screen readers (inspect the DOM to check these):

Name
Street address
City
State
Feest, Bogan and Herzog21716 Ratke DriveStromanportWY
Cummerata - Kuhlman6389 Dicki StreamSouth GateNH
Goyette Inc8873 Mertz RapidDorthysideID
Runte Inc2996 Ronny MountMcAllenMA
Goldner, Rohan and Lehner632 Broadway AvenueNorth LouieWY
Doyle, Hodkiewicz and O'Connell576 Joyce WaysTyraburghKS
Rau - O'Hara7508 Lansdowne RoadShieldsboroughMI
Tillman - Jacobi57918 Gwendolyn CirclesSheridanportMI
Connelly, Feest and Hodkiewicz7057 Stanley RoadKearaburghCA
Shanahan, Robel and Beier378 Berta CrescentWest GerryKS
Kling - McLaughlin8346 Kertzmann SquareSouth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
Jogi - McLaughlin83462 Shazam StreetNorth JoesphID
No records

Selecting all records on all pages

When using pagination, the best practice is to only load the current page’s records from the server.
This also means that Mantine DataTable can’t—and shouldn’t—know about your entire dataset, so the “select all” checkbox will only select/deselect the records on the currently visible page.

However, in certain you might want to give users the ability to “select all records on all pages” (like you have in Gmail’s user interface). In this case, you can use the allRecordsSelectionCheckboxProps to create your own selection mechanism:

First name
Last name
Email
Department
Company
JeraldHowellJerald.Howell32@yahoo.comIndustrialRunte Inc
KathleenRueckerKathleen_Ruecker@hotmail.comComputersShanahan, Robel and Beier
EricaVolkmanErica.Volkman37@gmail.comToysGoyette Inc
CliffordOberbrunnerClifford.Oberbrunner@hotmail.comAutomotiveRau - O'Hara
AlisonKlingAlison16@gmail.comJeweleryGoyette Inc
SueZiemeSue.Zieme29@hotmail.comBooksCummerata - Kuhlman
FeliciaGleasonFelicia30@yahoo.comShoesDoyle, Hodkiewicz and O'Connell
AlfredoZemlakAlfredo22@yahoo.comGamesRunte Inc
EmilyBartolettiEmily.Bartoletti@gmail.comAutomotiveRau - O'Hara
DeloresReynoldsDelores.Reynolds@yahoo.comIndustrialRunte Inc
1 - 10 / 500
No records

You have selected 0 records of a total of 500.

Here is the code for the above example:

const PAGE_SIZE = 10;

const [page, setPage] = useState(1);
const [records, setRecords] = useState(employees.slice(0, PAGE_SIZE));
const [allRecordsSelected, setAllRecordsSelected] = useState(false);
const [selectedRecords, setSelectedRecords] = useState<Employee[]>([]);
const [unselectedRecords, setUnselectedRecords] = useState<Employee[]>([]);

const handleSelectedRecordsChange = (newSelectedRecords: Employee[]) => {
  if (allRecordsSelected) {
    const recordsToUnselect = records.filter((record) => !newSelectedRecords.includes(record));
    setUnselectedRecords(
      // 👇 `uniqBy` is a utility function provided by Mantine DataTable
      uniqBy([...unselectedRecords, ...recordsToUnselect], (r) => r.id).filter((r) => !newSelectedRecords.includes(r))
    );
  } else {
    setSelectedRecords(newSelectedRecords);
  }
};

const handleAllRecordsSelectionCheckboxChange = () => {
  if (allRecordsSelected) {
    setAllRecordsSelected(false);
    setSelectedRecords([]);
    setUnselectedRecords([]);
  } else {
    setAllRecordsSelected(true);
  }
};

useEffect(() => {
  const from = (page - 1) * PAGE_SIZE;
  const to = from + PAGE_SIZE;
  const currentRecords = employees.slice(from, to);
  setRecords(currentRecords);
  if (allRecordsSelected) {
    setSelectedRecords(
      // 👇 `differenceBy` is a utility function provided by Mantine DataTable
      differenceBy(currentRecords, unselectedRecords, (r) => r.id)
    );
  }
}, [allRecordsSelected, page, unselectedRecords]);

return (
  <>
    <DataTable
      selectedRecords={selectedRecords}
      onSelectedRecordsChange={handleSelectedRecordsChange}
      allRecordsSelectionCheckboxProps={{
        indeterminate: allRecordsSelected && !!unselectedRecords.length,
        checked: allRecordsSelected,
        onChange: handleAllRecordsSelectionCheckboxChange,
        title: allRecordsSelected ? 'Unselect all records' : `Select ${employees.length} records`,
      }}
      records={records}
      totalRecords={employees.length}
      recordsPerPage={PAGE_SIZE}
      page={page}
      onPageChange={(p) => setPage(p)}
      // other table props...
    />
    <Paper p="md" mt="sm" withBorder>
      <Text size="sm" ta="center">
        You have selected {allRecordsSelected ? employees.length - unselectedRecords.length : selectedRecords.length}{' '}
        records of a total of {employees.length}.
      </Text>
    </Paper>
  </>
);

Horizontal scrolling behavior

Notice how, when the table needs to be horizontally scrollable, the selection column will be fixed to the left side of the table, so that the selection checkboxes are always visible:

First name
Last name
Email
Department
Company
Company mission statement
Street address
City
State
JeraldHowellJerald.Howell32@yahoo.comIndustrialRunte IncEngage synergistic infrastructures.2996 Ronny MountMcAllenMA
KathleenRueckerKathleen_Ruecker@hotmail.comComputersShanahan, Robel and BeierSynthesize customized portals.378 Berta CrescentWest GerryKS
EricaVolkmanErica.Volkman37@gmail.comToysGoyette IncProductize front-end web services.8873 Mertz RapidDorthysideID
CliffordOberbrunnerClifford.Oberbrunner@hotmail.comAutomotiveRau - O'HaraInnovate real-time applications.7508 Lansdowne RoadShieldsboroughMI
AlisonKlingAlison16@gmail.comJeweleryGoyette IncProductize front-end web services.8873 Mertz RapidDorthysideID
No records

Code:

const [selectedRecords, setSelectedRecords] = useState<Employee[]>([]);

return (
  <DataTable
    selectedRecords={selectedRecords}
    onSelectedRecordsChange={setSelectedRecords}
    // 👇 these columns take up more horizontal space
    columns={[
      { accessor: 'firstName' },
      { accessor: 'lastName' },
      { accessor: 'email' },
      { accessor: 'department.name', title: 'Department' },
      { accessor: 'department.company.name', title: 'Company', noWrap: true },
      { accessor: 'department.company.missionStatement', title: 'Company mission statement', noWrap: true },
      { accessor: 'department.company.streetAddress', title: 'Street address', noWrap: true },
      { accessor: 'department.company.city', title: 'City', noWrap: true },
      { accessor: 'department.company.state', title: 'State', textAlign: 'right' },
    ]}
    // other table props...
  />
);

Maximizing the selection trigger area to the entire cell

By default, selection is triggered when the user clicks the row selection checkbox.
However, you can maximize the trigger area to the entire cell holding the checkbox by setting the selectionTrigger property value to cell:

<DataTable
  // other props...
  selectionTrigger="cell" // 👈 click anywhere in the cell to select the record
/>

In this case, clicking anywhere in the cell will result in selecting/deselecting the underlying record:

Name
Address
Mission statement
Feest, Bogan and Herzog
21716 Ratke Drive
Stromanport
WY
Innovate bricks-and-clicks metrics.
Cummerata - Kuhlman
6389 Dicki Stream
South Gate
NH
Harness real-time channels.
Goyette Inc
8873 Mertz Rapid
Dorthyside
ID
Productize front-end web services.
No records

Head over to the next example to discover more features.