Skip to content

Commit 65a0bd6

Browse files
authored
Merge pull request #762 from icflorescu/next
Prepare v8.3.6
2 parents f184223 + aa6d551 commit 65a0bd6

25 files changed

+1387
-840
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
The following is a list of notable changes to the Mantine DataTable component.
44
Minor versions that are not listed in the changelog are bug fixes and small improvements.
55

6+
## 8.3.6 (2025-11-07)
7+
8+
- Merge [#740](https://github.com/icflorescu/mantine-datatable/pull/740) to fix [#739](https://github.com/icflorescu/mantine-datatable/issues/739)
9+
- Merge [#741](https://github.com/icflorescu/mantine-datatable/pull/741) to fix [#640](https://github.com/icflorescu/mantine-datatable/issues/640)
10+
- Merge [#746](https://github.com/icflorescu/mantine-datatable/pull/746) to fix [#745](https://github.com/icflorescu/mantine-datatable/issues/745)
11+
- Merge [#747](https://github.com/icflorescu/mantine-datatable/pull/747) to implement `renderPagination` prop for full pagination customization
12+
- Merge [#749](https://github.com/icflorescu/mantine-datatable/pull/749) which improves auto resize
13+
- Merge [#750](https://github.com/icflorescu/mantine-datatable/pull/750) which adds multilevel column grouping support
14+
- Merge [#761](https://github.com/icflorescu/mantine-datatable/pull/761) to fix [#692](https://github.com/icflorescu/mantine-datatable/issues/692)
15+
- Update deps to ensure compatibility with Mantine 8.3.6
16+
617
## 8.2.0 (2025-07-23)
718

819
- **Significant performance improvement by reducing re-renders**, many thanks to [yergom](https://github.com/yergom) for PR [#732](https://github.com/icflorescu/mantine-datatable/pull/732)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'use client';
2+
3+
import { DataTable } from '__PACKAGE__';
4+
import { employees } from '~/data';
5+
6+
export function MultilevelColumnGroupingExample() {
7+
return (
8+
<DataTable
9+
withTableBorder
10+
withColumnBorders
11+
records={employees.slice(0, 10)}
12+
groups={[
13+
{
14+
id: 'personal-info',
15+
title: 'Personal Information',
16+
groups: [
17+
{
18+
id: 'name-group',
19+
title: 'Name',
20+
columns: [
21+
{
22+
accessor: 'firstName',
23+
title: 'First Name',
24+
width: 120,
25+
},
26+
{
27+
accessor: 'lastName',
28+
title: 'Last Name',
29+
width: 120,
30+
},
31+
],
32+
},
33+
{
34+
id: 'demographics',
35+
title: 'Demographics',
36+
columns: [
37+
{
38+
accessor: 'sex',
39+
title: 'Gender',
40+
width: 80,
41+
},
42+
{
43+
accessor: 'birthDate',
44+
title: 'Birth Date',
45+
width: 120,
46+
render: ({ birthDate }) => new Date(birthDate).toLocaleDateString(),
47+
},
48+
],
49+
},
50+
],
51+
},
52+
{
53+
id: 'contact-info',
54+
title: 'Contact Information',
55+
groups: [
56+
{
57+
id: 'email-group',
58+
title: 'Email',
59+
columns: [
60+
{
61+
accessor: 'email',
62+
title: 'Email Address',
63+
width: 250,
64+
ellipsis: true,
65+
},
66+
],
67+
},
68+
],
69+
},
70+
{
71+
id: 'work-info',
72+
title: 'Work Information',
73+
groups: [
74+
{
75+
id: 'identifiers',
76+
title: 'IDs',
77+
columns: [
78+
{
79+
accessor: 'id',
80+
title: 'Employee ID',
81+
width: 100,
82+
ellipsis: true,
83+
},
84+
{
85+
accessor: 'department.id',
86+
title: 'Department ID',
87+
width: 100,
88+
ellipsis: true,
89+
},
90+
],
91+
},
92+
],
93+
},
94+
]}
95+
/>
96+
);
97+
}

app/examples/column-grouping/page.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import { CodeBlock } from '~/components/CodeBlock';
44
import { ExternalLink } from '~/components/ExternalLink';
55
import { InternalLink } from '~/components/InternalLink';
66
import { PageNavigation } from '~/components/PageNavigation';
7+
import { PageSubtitle } from '~/components/PageSubtitle';
78
import { PageTitle } from '~/components/PageTitle';
89
import { Txt } from '~/components/Txt';
910
import { UnorderedList } from '~/components/UnorderedList';
1011
import { readCodeFile } from '~/lib/code';
1112
import { allPromiseProps, getRouteMetadata } from '~/lib/utils';
1213
import { ColumnGroupingExample } from './ColumnGroupingExample';
14+
import { MultilevelColumnGroupingExample } from './MultilevelColumnGroupingExample';
1315

1416
const PATH: Route = '/examples/column-grouping';
1517

@@ -18,6 +20,7 @@ export const metadata = getRouteMetadata(PATH);
1820
export default async function ColumnGroupingExamplePage() {
1921
const code = await allPromiseProps({
2022
'ColumnGroupingExample.tsx': readCodeFile<string>(`${PATH}/ColumnGroupingExample.tsx`),
23+
'MultilevelColumnGroupingExample.tsx': readCodeFile<string>(`${PATH}/MultilevelColumnGroupingExample.tsx`),
2124
'companies.json': readCodeFile<string>('/../data/companies.json'),
2225
});
2326

@@ -83,6 +86,10 @@ export default async function ColumnGroupingExamplePage() {
8386
<ColumnGroupingExample />
8487
<Txt>Here is the code used to generate the table above:</Txt>
8588
<CodeBlock tabs={{ code, keys: ['ColumnGroupingExample.tsx', 'companies.json'] }} />
89+
<PageSubtitle value="Multilevel column grouping" />
90+
<MultilevelColumnGroupingExample />
91+
<Txt>Here is the code used to generate the table above:</Txt>
92+
<CodeBlock tabs={{ code, keys: ['MultilevelColumnGroupingExample.tsx', 'companies.json'] }} />
8693
<Txt>Head over to the next example to discover more features.</Txt>
8794
<PageNavigation of={PATH} />
8895
</>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
'use client';
2+
3+
import { Group, NumberInput, Text } from '@mantine/core';
4+
import { DataTable } from '__PACKAGE__';
5+
import dayjs from 'dayjs';
6+
import { useEffect, useState } from 'react';
7+
import employees from '~/data/employees.json';
8+
9+
const PAGE_SIZES = [10, 15, 20];
10+
11+
export default function PaginationCustomRenderExample() {
12+
const [pageSize, setPageSize] = useState(PAGE_SIZES[1]);
13+
14+
useEffect(() => {
15+
setPage(1);
16+
}, [pageSize]);
17+
18+
const [page, setPage] = useState(1);
19+
const [records, setRecords] = useState(employees.slice(0, pageSize));
20+
21+
useEffect(() => {
22+
const from = (page - 1) * pageSize;
23+
const to = from + pageSize;
24+
setRecords(employees.slice(from, to));
25+
}, [page, pageSize]);
26+
27+
const max = Math.ceil(employees.length / pageSize);
28+
29+
return (
30+
// example-start
31+
<DataTable
32+
// example-skip other props
33+
withTableBorder
34+
records={records}
35+
columns={[
36+
{ accessor: 'firstName', width: 100 },
37+
{ accessor: 'lastName', width: 100 },
38+
{ accessor: 'email', width: '100%' },
39+
{
40+
accessor: 'birthDate',
41+
textAlign: 'right',
42+
width: 120,
43+
render: ({ birthDate }) => dayjs(birthDate).format('MMM D YYYY'),
44+
},
45+
]}
46+
totalRecords={employees.length}
47+
recordsPerPage={pageSize}
48+
page={page}
49+
onPageChange={(p) => setPage(p)}
50+
recordsPerPageOptions={PAGE_SIZES}
51+
onRecordsPerPageChange={setPageSize}
52+
// example-resume
53+
// 👇 custom "Jump to page" control using renderPagination callback
54+
renderPagination={({ state, actions, Controls }) => (
55+
<>
56+
<Controls.Text />
57+
<Controls.PageSizeSelector />
58+
<Group gap="xs">
59+
<Text size={state.paginationSize}>Jump to page</Text>
60+
<NumberInput
61+
hideControls
62+
w={80}
63+
size={state.paginationSize}
64+
onChange={(p) => typeof p === 'number' && actions.setPage(p)}
65+
min={1}
66+
max={max}
67+
value={page}
68+
/>
69+
</Group>
70+
<Controls.Pagination />
71+
</>
72+
)}
73+
/>
74+
// example-end
75+
);
76+
}

app/examples/pagination/page.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Code } from '@mantine/core';
22
import type { Route } from 'next';
33
import { Fragment } from 'react';
44
import { PRODUCT_NAME } from '~/app/config';
5+
import PaginationCustomRenderExample from '~/app/examples/pagination/PaginationCustomRenderExample';
56
import { CodeBlock } from '~/components/CodeBlock';
67
import { PageNavigation } from '~/components/PageNavigation';
78
import { PageSubtitle } from '~/components/PageSubtitle';
@@ -23,6 +24,7 @@ export default async function PaginationExamplePage() {
2324
const code = await allPromiseProps({
2425
'PaginationExample.tsx': readCodeFile<string>(`${PATH}/PaginationExample.tsx`),
2526
'PaginationExampleWithControlProps.tsx': readCodeFile<string>(`${PATH}/PaginationExampleWithControlProps.tsx`),
27+
'PaginationCustomRenderExample.tsx': readCodeFile<string>(`${PATH}/PaginationCustomRenderExample.tsx`),
2628
'PaginationExampleWithPageSizeSelector.tsx': readCodeFile<string>(
2729
`${PATH}/PaginationExampleWithPageSizeSelector.tsx`
2830
),
@@ -150,6 +152,28 @@ export default async function PaginationExamplePage() {
150152
</UnorderedList>
151153
<CodeBlock code={code['PaginationExampleWithPageSizeSelector.tsx']} />
152154
<PaginationExampleWithPageSizeSelector />
155+
156+
<PageSubtitle value="Customizing pagination controls" />
157+
<Txt>
158+
You can fully customize pagination by providing the <Code>renderPagination</Code> prop. The callback receives a
159+
context with default controls as factories:
160+
<UnorderedList>
161+
<li>
162+
<Code>Controls.Text</Code>: the pagination text.
163+
</li>
164+
<li>
165+
<Code>Controls.PageSizeSelector</Code>: the page size selector (if enabled).
166+
</li>
167+
<li>
168+
<Code>Controls.Pagination</Code>: the pagination component.
169+
</li>
170+
</UnorderedList>
171+
This allows you to render them in any order, inject your own elements, or override their props. The example
172+
below shows how to add a &quot;jump to page&quot; control between page size selector and pagination controls.
173+
</Txt>
174+
<CodeBlock code={code['PaginationCustomRenderExample.tsx']} />
175+
<PaginationCustomRenderExample />
176+
153177
<PageSubtitle value="Using pagination control props" />
154178
<Txt>
155179
You can provide additional props to pagination controls by using the <Code>getPaginationControlProps</Code>{' '}

components/CodeBlock.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { CodeHighlight, CodeHighlightTabs } from '@mantine/code-highlight';
2-
import { IconBrandCss3, IconBrandTypescript, IconFileTypeTsx, IconTerminal } from '@tabler/icons-react';
2+
import {
3+
IconBrandCss3,
4+
IconBrandJavascript,
5+
IconBrandTypescript,
6+
IconFileTypeTsx,
7+
IconTerminal,
8+
} from '@tabler/icons-react';
39
import classes from './CodeBlock.module.css';
410

511
const ICON_PROPS = { size: 16 };
612

713
const ICONS = {
814
tsx: <IconFileTypeTsx {...ICON_PROPS} />,
915
ts: <IconBrandTypescript {...ICON_PROPS} />,
16+
js: <IconBrandJavascript {...ICON_PROPS} />,
1017
css: <IconBrandCss3 {...ICON_PROPS} />,
1118
shell: <IconTerminal {...ICON_PROPS} />,
1219
};

components/ShikiCodeHighlightProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { PropsWithChildren } from 'react';
66
async function loadShiki() {
77
const { createHighlighter } = await import('shiki');
88
const shiki = await createHighlighter({
9-
langs: ['ts', 'tsx', 'json', 'css', 'shell'],
9+
langs: ['ts', 'tsx', 'js', 'json', 'css', 'shell'],
1010
themes: [],
1111
});
1212

next.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ module.exports = async () => {
1313
output: 'export',
1414
trailingSlash: true,
1515
images: { unoptimized: true },
16+
typedRoutes: true,
1617
experimental: {
17-
typedRoutes: true,
1818
optimizePackageImports: [
1919
'@mantine/code-highlight',
2020
'@mantine/core',

package.json

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mantine-datatable",
3-
"version": "8.2.0",
3+
"version": "8.3.6",
44
"description": "The lightweight, dependency-free, dark-theme aware table component for your Mantine UI data-rich applications, featuring asynchronous data loading support, pagination, intuitive Gmail-style additive batch rows selection, column sorting, custom cell data rendering, row expansion, nesting, context menus, and much more",
55
"keywords": [
66
"mantine",
@@ -75,48 +75,48 @@
7575
"@docsearch/react": "^3.9.0",
7676
"@eslint/eslintrc": "^3.3.1",
7777
"@faker-js/faker": "^9.9.0",
78-
"@formkit/auto-animate": "^0.8.2",
78+
"@formkit/auto-animate": "^0.9.0",
7979
"@hello-pangea/dnd": "^18.0.1",
80-
"@mantine/code-highlight": "^8.2.1",
81-
"@mantine/core": "^8.2.1",
82-
"@mantine/dates": "^8.2.1",
83-
"@mantine/hooks": "^8.2.1",
84-
"@mantine/modals": "^8.2.1",
85-
"@mantine/notifications": "^8.2.1",
86-
"@tabler/icons-react": "^3.34.1",
87-
"@tanstack/react-query": "^5.83.0",
80+
"@mantine/code-highlight": "^8.3.6",
81+
"@mantine/core": "^8.3.6",
82+
"@mantine/dates": "^8.3.6",
83+
"@mantine/hooks": "^8.3.6",
84+
"@mantine/modals": "^8.3.6",
85+
"@mantine/notifications": "^8.3.6",
86+
"@tabler/icons-react": "^3.35.0",
87+
"@tanstack/react-query": "^5.90.7",
8888
"@types/lodash": "^4.17.20",
89-
"@types/node": "^24.1.0",
90-
"@types/react": "^19.1.8",
91-
"@types/react-dom": "^19.1.6",
92-
"@typescript-eslint/eslint-plugin": "^8.38.0",
93-
"@typescript-eslint/parser": "^8.38.0",
89+
"@types/node": "^24.10.0",
90+
"@types/react": "^19.2.2",
91+
"@types/react-dom": "^19.2.2",
92+
"@typescript-eslint/eslint-plugin": "^8.46.3",
93+
"@typescript-eslint/parser": "^8.46.3",
9494
"clsx": "^2.1.1",
95-
"cssnano": "^7.1.0",
96-
"dayjs": "^1.11.13",
97-
"eslint": "^9.31.0",
98-
"eslint-config-next": "^15.4.3",
95+
"cssnano": "^7.1.2",
96+
"dayjs": "^1.11.19",
97+
"eslint": "^9.39.1",
98+
"eslint-config-next": "^15.5.6",
9999
"eslint-config-prettier": "^10.1.8",
100100
"lodash": "^4.17.21",
101-
"mantine-contextmenu": "^8.2.0",
102-
"next": "^15.4.3",
101+
"mantine-contextmenu": "^8.3.6",
102+
"next": "^15.5.6",
103103
"postcss": "^8.5.6",
104104
"postcss-cli": "^11.0.1",
105105
"postcss-import": "^16.1.1",
106106
"postcss-preset-mantine": "^1.18.0",
107107
"postcss-simple-vars": "^7.0.1",
108108
"prettier": "^3.6.2",
109-
"react": "^19.1.0",
110-
"react-dom": "^19.1.0",
111-
"sharp": "^0.34.3",
112-
"shiki": "^3.8.1",
113-
"swr": "^2.3.4",
109+
"react": "^19.2.0",
110+
"react-dom": "^19.2.0",
111+
"sharp": "^0.34.5",
112+
"shiki": "^3.15.0",
113+
"swr": "^2.3.6",
114114
"tsup": "^8.5.0",
115-
"typescript": "^5.8.3"
115+
"typescript": "^5.9.3"
116116
},
117117
"peerDependencies": {
118-
"@mantine/core": ">=8.1",
119-
"@mantine/hooks": ">=8.1",
118+
"@mantine/core": ">=8.3",
119+
"@mantine/hooks": ">=8.3",
120120
"clsx": ">=2",
121121
"react": ">=19",
122122
"react-dom": ">=19"

0 commit comments

Comments
 (0)