### Complex Column Dragging and Toggling Example Source: https://icflorescu.github.io/mantine-datatable/examples/column-dragging-and-toggling This example demonstrates a complex setup for column dragging and toggling. It utilizes `useDataTableColumns` for managing column state and integrates context menus for resetting column order and toggled visibility. Ensure `mantine-datatable`, `@tabler/icons-react`, and `lodash` are installed. ```tsx 'use client'; import { DataTable, type DataTableSortStatus, useDataTableColumns } from 'mantine-datatable'; import { IconColumnRemove, IconColumns3 } from '@tabler/icons-react'; import sortBy from 'lodash/sortBy'; import { useContextMenu } from 'mantine-contextmenu'; import { useEffect, useState } from 'react'; import { type Company, companies } from '~/data'; export default function DraggingTogglingComplexExample() { const { showContextMenu } = useContextMenu(); const [sortStatus, setSortStatus] = useState>({ columnAccessor: 'name', direction: 'asc', }); const [records, setRecords] = useState(sortBy(companies, 'name')); useEffect(() => { const data = sortBy(companies, sortStatus.columnAccessor) as Company[]; setRecords(sortStatus.direction === 'desc' ? data.reverse() : data); }, [sortStatus]); const key = 'toggleable-reset-example'; const { effectiveColumns, resetColumnsOrder, resetColumnsToggle } = useDataTableColumns({ key, columns: [ { accessor: 'name', width: '40%', toggleable: true, draggable: true, sortable: true }, { accessor: 'streetAddress', width: '60%', toggleable: true, draggable: true }, { accessor: 'city', width: 160, toggleable: true, draggable: true }, { accessor: 'state', textAlign: 'right' }, ], }); return ( showContextMenu([ { key: 'reset-toggled-columns', icon: , onClick: resetColumnsToggle, }, { key: 'reset-columns-order', icon: , onClick: resetColumnsOrder, }, ])(event) } /> ); } ``` -------------------------------- ### Basic DataTable with Columns and Records Source: https://icflorescu.github.io/mantine-datatable/examples/basic-table-properties This snippet shows a fundamental DataTable setup with defined columns and data records. It's a starting point for displaying tabular data. ```jsx return ( ); ``` -------------------------------- ### Enable and Customize Pagination Source: https://icflorescu.github.io/mantine-datatable/examples/pagination This example shows how to enable basic pagination by setting `totalRecords`, `recordsPerPage`, `page`, and `onPageChange`. It also includes commented-out examples for customizing `paginationSize`, `loadingText`, `noRecordsText`, `paginationText`, and pagination colors. ```javascript 'use client'; import { DataTable } from 'mantine-datatable'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; import employees from '~/data/employees.json'; const PAGE_SIZE = 15; export default function PaginationExample() { const [page, setPage] = useState(1); const [records, setRecords] = useState(employees.slice(0, PAGE_SIZE)); useEffect(() => { const from = (page - 1) * PAGE_SIZE; const to = from + PAGE_SIZE; setRecords(employees.slice(from, to)); }, [page]); return ( dayjs(birthDate).format('MMM D YYYY'), }, ]} totalRecords={employees.length} recordsPerPage={PAGE_SIZE} page={page} onPageChange={(p) => setPage(p)} // 👇 uncomment the next line to use a custom pagination size // paginationSize="md" // 👇 uncomment the next line to use a custom loading text // loadingText="Loading..." // 👇 uncomment the next line to display a custom text when no records were found // noRecordsText="No records found" // 👇 uncomment the next line to use a custom pagination text // paginationText={({ from, to, totalRecords }) => `Records ${from} - ${to} of ${totalRecords}`} // 👇 uncomment the next lines to use custom pagination colors // paginationActiveBackgroundColor="green" // paginationActiveTextColor="#e6e348" /> ); } ``` -------------------------------- ### Column Grouping Example Source: https://icflorescu.github.io/mantine-datatable/examples/column-grouping This example shows how to group columns for company information and contact details. It includes examples of custom styling, conditional visibility, and empty groups. ```tsx 'use client'; import { DataTable } from 'mantine-datatable'; import { companies } from '~/data'; export function ColumnGroupingExample() { return ( `(min-width: ${theme.breakpoints.md})` }, ], }, { id: 'contact-info', title: 'Contact information', textAlign: 'center', style: (theme) => ({ color: theme.colors.blue[6] }), columns: [{ accessor: 'streetAddress' }, { accessor: 'city' }, { accessor: 'state', textAlign: 'right' }], }, // 👇 all columns in this group are hidden, so it will not be rendered { id: 'other', columns: [{ accessor: 'id', hidden: true }], }, // 👇 this group has no columns, so it will not be rendered { id: 'empty-group', title: 'Empty group', columns: [], }, ]} /> ); } ``` -------------------------------- ### Install Mantine DataTable Source: https://icflorescu.github.io/mantine-datatable/getting-started Install Mantine DataTable and clsx using yarn. Ensure you have @mantine/core and @mantine/hooks installed. ```bash yarn add mantine-datatable clsx ``` -------------------------------- ### Basic Column Rendering Example Source: https://icflorescu.github.io/mantine-datatable/examples/column-properties-and-styling Demonstrates a basic column configuration using a render function to display the age calculated from a birth date. ```javascript render: ({ birthDate }) => dayjs().diff(birthDate, 'years') }, ]} /> ); } ``` -------------------------------- ### Complex Mantine DataTable Example with Async Data Source: https://icflorescu.github.io/mantine-datatable/examples/complex-usage-scenario A comprehensive example of Mantine DataTable demonstrating asynchronous data fetching using TanStack Query, pagination, sorting, row selection, context menus, and action modals. It requires setup with QueryClientProvider. ```tsx 'use client'; import type { DataTableColumn, DataTableProps, DataTableSortStatus } from 'mantine-datatable'; import { DataTable } from 'mantine-datatable'; import type { MantineTheme } from '@mantine/core'; import { ActionIcon, Button, Center, Flex, Group, Image, rem, Text, TextInput } from '@mantine/core'; import { closeAllModals, openModal } from '@mantine/modals'; import { showNotification } from '@mantine/notifications'; import { IconClick, IconEdit, IconMessage, IconTrash, IconTrashX } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; import dayjs from 'dayjs'; import { useContextMenu } from 'mantine-contextmenu'; import { useCallback, useState } from 'react'; import type { Employee } from '~/data'; import { getEmployeesAsync } from '~/data/async'; import classes from './ComplexUsageExample.module.css'; const PAGE_SIZE = 100; export function ComplexUsageExample() { const { showContextMenu, hideContextMenu } = useContextMenu(); const [page, setPage] = useState(1); const [sortStatus, setSortStatus] = useState>({ columnAccessor: 'name', direction: 'asc', }); const { data, isFetching } = useQuery({ queryKey: ['employees', sortStatus.columnAccessor, sortStatus.direction, page], queryFn: () => getEmployeesAsync({ recordsPerPage: PAGE_SIZE, page, sortStatus, delay: { min: 300, max: 500 } }), }); const [selectedRecords, setSelectedRecords] = useState([]); const handleSortStatusChange = (status: DataTableSortStatus) => { setPage(1); setSortStatus(status); }; const editRecord = useCallback(({ firstName, lastName }: Employee) => { showNotification({ withBorder: true, title: 'Editing record', message: `In a real application we could show a popup to edit ${firstName} ${lastName}, but this is just a demo, so we're not going to do that`, }); }, []); const deleteRecord = useCallback(({ firstName, lastName }: Employee) => { showNotification({ withBorder: true, color: 'red', title: 'Deleting record', message: `Should delete ${firstName} ${lastName}, but we're not going to, because this is just a demo`, }); }, []); const deleteSelectedRecords = useCallback(() => { showNotification({ withBorder: true, color: 'red', title: 'Deleting multiple records', message: `Should delete ${selectedRecords.length} records, but we're not going to do that because deleting data is bad... and this is just a demo anyway`, }); }, [selectedRecords.length]); const sendMessage = useCallback(({ firstName, lastName }: Employee) => { showNotification({ withBorder: true, title: 'Sending message', message: `A real application could send a message to ${firstName} ${lastName}, but this is just a demo and we're not going to do that because we don't have a backend`, color: 'green', }); }, []); const renderActions: DataTableColumn['render'] = (record) => ( { e.stopPropagation(); // 👈 prevent triggering the row click function openModal({ title: `Send message to ${record.firstName} ${record.lastName}`, classNames: { header: classes.modalHeader, title: classes.modalTitle }, children: ( <> ), }); }} > { e.stopPropagation(); editRecord(record); }} > { e.stopPropagation(); deleteRecord(record); }} > ); const columns: DataTableColumn[] = [ { accessor: 'firstName', title: 'First Name', sortable: true, customSort: ([, direction], { firstName }) => { if (direction === 'asc') return firstName.localeCompare(firstName); return firstName.localeCompare(firstName) * -1; }, }, { accessor: 'lastName', title: 'Last Name', sortable: true, }, { accessor: 'email', title: 'Email', }, { accessor: 'gender', title: 'Gender', width: 100, textAlign: 'center', }, { accessor: 'jobTitle', title: 'Job Title', }, { accessor: 'lastSeen', title: 'Last Seen', width: 150, render: (text) => dayjs(text).format('MMM D, YYYY'), customSort: ([, direction], { lastSeen: a }, { lastSeen: b }) => { if (direction === 'asc') return dayjs(a).diff(dayjs(b)); return dayjs(b).diff(dayjs(a)); }, }, { accessor: 'actions', title: (
), render: renderActions, width: 100, // 👈 disable sorting for this column sortable: false, }, ]; return ( { event.preventDefault(); showContextMenu({ id: 'row-context-menu', triggerEvent: event, items: [ { title: 'Edit', onClick: () => editRecord(record) }, { title: 'Send message', onClick: () => sendMessage(record) }, { title: 'Delete', color: 'red', onClick: () => deleteRecord(record) }, ], }); }} fetching={isFetching} totalRecords={data?.totalRecords || 0} recordsPerPage={PAGE_SIZE} page={page} onPageChange={setPage} sortStatus={sortStatus} onSortStatusChange={handleSortStatusChange} columns={columns} striped highlightOnHover withTableBorder // 👈 enable row selection // 👈 enable context menu // 👈 enable fetching state // 👈 enable pagination // 👈 enable sorting /> ); } ``` -------------------------------- ### Full-Featured RTL Table Example Source: https://icflorescu.github.io/mantine-datatable/examples/rtl-support Illustrates a comprehensive Mantine DataTable setup with pinned columns, row selection, sorting, pagination, and column resizing, all adapted for RTL layouts. This is for complex tables requiring advanced features in an RTL environment. ```tsx // Example 3: With pinned columns, selection, sorting, pagination, and resizing export function RTLFullFeaturedExample({ direction }: { direction: 'ltr' | 'rtl' }) { const PAGE_SIZES = [5, 10, 20]; const [page, setPage] = useState(1); ``` -------------------------------- ### Basic Mantine DataTable Example Source: https://icflorescu.github.io/mantine-datatable/getting-started A simple example demonstrating how to use the Mantine DataTable component with sample records and column definitions. It includes basic styling and row click handling. ```tsx 'use client'; import { DataTable } from 'mantine-datatable'; import { Box } from '@mantine/core'; import { showNotification } from '@mantine/notifications'; export function GettingStartedExample() { return ( ( {party.slice(0, 3).toUpperCase()} ), }, { accessor: 'bornIn' }, ]} // execute this callback when a row is clicked onRowClick={({ record: { name, party, bornIn } }) => showNotification({ title: `Clicked on ${name}`, message: `You clicked on ${name}, a ${party.toLowerCase()} president born in ${bornIn}`, withBorder: true, }) } /> ); } ``` -------------------------------- ### Row Context Menu Example Source: https://icflorescu.github.io/mantine-datatable/examples/using-with-mantine-contextmenu Implement a context menu for each row in the DataTable. This example shows how to display options like view, edit, and delete when a row is right-clicked. It also disables text selection on touch devices for better usability. ```javascript 'use client'; // 👆 Since 'useContextMenu' is a hook, don't forget to add the 'use client' directive // at the top of your file if you're using it in a RSC context import { DataTable } from 'mantine-datatable'; import { useMediaQuery } from '@mantine/hooks'; import { showNotification } from '@mantine/notifications'; import { IconEdit, IconEye, IconTrash } from '@tabler/icons-react'; import { useContextMenu } from 'mantine-contextmenu'; import companies from '~/data/companies.json'; export function RowContextMenuExample() { const { showContextMenu } = useContextMenu(); const isTouch = useMediaQuery('(pointer: coarse)'); return ( showContextMenu([ { key: 'view-company-details', icon: , onClick: () => showNotification({ message: `Clicked on view context-menu action for ${record.name} company`, withBorder: true, }), }, { key: 'edit-company-information', icon: , onClick: () => showNotification({ message: `Clicked on edit context-menu action for ${record.name} company`, withBorder: true, }), }, { key: 'divider' }, { key: 'delete-company', icon: , color: 'red', onClick: () => showNotification({ color: 'red', message: `Clicked on delete context-menu action for ${record.name} company`, withBorder: true, }), }, ])(event) } /> ); } ``` -------------------------------- ### Column Properties and Styling Example Source: https://icflorescu.github.io/mantine-datatable/examples/column-properties-and-styling Demonstrates various column properties including width, text alignment, ellipsis truncation, and conditional visibility using media queries. It also shows how to render custom content and access nested properties. ```tsx 'use client'; import { DataTable } from 'mantine-datatable'; import dayjs from 'dayjs'; import { employees } from '~/data'; const records = employees.slice(0, 10); export function ColumnPropertiesExample() { return ( records.indexOf(record) + 1, }, { accessor: 'name', title: 'Full name', render: ({ firstName, lastName }) => `${firstName} ${lastName}`, width: 160, }, { accessor: 'email' }, { accessor: 'department.name', width: 150 }, { // 👇 using dot-notation to access nested object property accessor: 'department.company.name', title: 'Company', width: 150, // 👇 truncate with ellipsis if text overflows the available width ellipsis: true, }, { accessor: 'birthDate', title: 'Birthday', width: 100, render: ({ birthDate }) => dayjs(birthDate).format('MMM D'), // 👇 column is only visible when screen width is over `theme.breakpoints.xs` visibleMediaQuery: (theme) => `(min-width: ${theme.breakpoints.xs})`, }, { // 👇 "virtual column" accessor: 'age', width: 60, textAlign: 'right', // 👇 column is only visible when screen width is over `theme.breakpoints.xs` visibleMediaQuery: (theme) => `(min-width: ${theme.breakpoints.xs})`, }, ]} /> ); } ``` -------------------------------- ### Implement Infinite Scrolling with onScrollToBottom Source: https://icflorescu.github.io/mantine-datatable/examples/infinite-scrolling This example shows how to use the `onScrollToBottom` callback to load more data when the user scrolls to the bottom of the table. It utilizes Mantine UI components and notifications for user feedback. ```javascript 'use client'; import { DataTable } from 'mantine-datatable'; import { Button, Group, Paper, Text } from '@mantine/core'; import { notifications } from '@mantine/notifications'; const records = [ { id: 1, firstName: 'Jerald', lastName: 'Howell', email: 'Jerald.Howell32@yahoo.com' }, { id: 2, firstName: 'Kathleen', lastName: 'Ruecker', email: 'Kathleen_Ruecker@hotmail.com' }, { id: 3, firstName: 'Erica', lastName: 'Volkman', email: 'Erica.Volkman37@gmail.com' }, { id: 4, firstName: 'Clifford', lastName: 'Oberbrunner', email: 'Clifford.Oberbrunner@hotmail.com' }, { id: 5, firstName: 'Alison', lastName: 'Kling', email: 'Alison16@gmail.com' }, { id: 6, firstName: 'Sue', lastName: 'Zieme', email: 'Sue.Zieme29@hotmail.com' }, { id: 7, firstName: 'Felicia', lastName: 'Gleason', email: 'Felicia30@yahoo.com' }, { id: 8, firstName: 'Alfredo', lastName: 'Zemlak', email: 'Alfredo22@yahoo.com' }, { id: 9, firstName: 'Emily', lastName: 'Bartoletti', email: 'Emily.Bartoletti@gmail.com' }, { id: 10, firstName: 'Delores', lastName: 'Reynolds', email: 'Delores.Reynolds@yahoo.com' }, { id: 11, firstName: 'Louis', lastName: 'Schamberger', email: 'Louis6@yahoo.com' }, { id: 12, firstName: 'Beverly', lastName: 'Heller', email: 'Beverly_Heller@gmail.com' }, { id: 13, firstName: 'Eugene', lastName: 'Feest', email: 'Eugene88@hotmail.com' }, { id: 14, firstName: 'Martin', lastName: 'Bahringer', email: 'Martin_Bahringer10@gmail.com' }, { id: 15, firstName: 'Ellis', lastName: 'Miller', email: 'Ellis36@hotmail.com' }, { id: 16, firstName: 'Gloria', lastName: 'Cole', email: 'Gloria41@gmail.com' }, { id: 17, firstName: 'Linda', lastName: 'Witting', email: 'Linda_Witting@yahoo.com' }, { id: 18, firstName: 'Gregg', lastName: 'Kutch', email: 'Gregg_Kutch8@yahoo.com' }, { id: 19, firstName: 'Mamie', lastName: 'Raynor', email: 'Mamie58@hotmail.com' }, { id: 20, firstName: 'Erick', lastName: 'Bruen', email: 'Erick_Bruen13@yahoo.com' }, { id: 21, firstName: 'Faith', lastName: 'Langworth', email: 'Faith_Langworth14@gmail.com' }, { id: 22, firstName: 'Alicia', lastName: 'Leannon', email: 'Alicia62@yahoo.com' }, { id: 23, firstName: 'Boyd', lastName: 'Mohr', email: 'Boyd.Mohr@hotmail.com' }, { id: 24, firstName: 'Lindsey', lastName: 'Heidenreich', email: 'Lindsey31@yahoo.com' }, { id: 25, firstName: 'Elsa', lastName: 'Marvin', email: 'Elsa.Marvin2@gmail.com' }, { id: 26, firstName: 'Debbie', lastName: 'Hagenes', email: 'Debbie.Hagenes@hotmail.com' }, { id: 27, firstName: 'Lionel', lastName: 'McCullough', email: 'Lionel_McCullough@gmail.com' }, { id: 28, firstName: 'Kim', lastName: 'Lebsack', email: 'Kim.Lebsack66@yahoo.com' }, { id: 29, firstName: 'Rolando', lastName: 'Weissnat', email: 'Rolando83@hotmail.com' }, { id: 30, firstName: 'Jacqueline', lastName: 'Lesch', email: 'Jacqueline35@hotmail.com' }, { id: 31, firstName: 'Felix', lastName: 'Stokes', email: 'Felix77@hotmail.com' }, { id: 32, firstName: 'Renee', lastName: 'Tillman', email: 'Renee.Tillman@yahoo.com' }, { id: 33, firstName: 'Richard', lastName: 'Watsica', email: 'Richard_Watsica@yahoo.com' }, { id: 34, firstName: 'Nathan', lastName: 'Wolf', email: 'Nathan.Wolf@gmail.com' }, { id: 35, firstName: 'Jonathan', lastName: 'Keebler-Crona', email: 'Jonathan.Keebler-Crona90@gmail.com' }, { id: 36, firstName: 'Kathleen', lastName: 'Spinka', email: 'Kathleen_Spinka58@hotmail.com' }, { id: 37, firstName: 'Bernice', lastName: 'Schinner', email: 'Bernice45@hotmail.com' }, { id: 38, firstName: 'Adam', lastName: 'Pagac', email: 'Adam58@hotmail.com' }, { id: 39, firstName: 'Earl', lastName: 'Ryan', email: 'Earl.Ryan@gmail.com' }, { id: 40, firstName: 'Greg', lastName: 'Bailey', email: 'Greg.Bailey@hotmail.com' }, { id: 41, firstName: 'Anne', lastName: 'Powlowski', email: 'Anne_Powlowski69@gmail.com' }, { id: 42, firstName: 'Abraham', lastName: 'Dooley', email: 'Abraham_Dooley@gmail.com' }, { id: 43, firstName: 'Myron', lastName: 'Lemke', email: 'Myron_Lemke@gmail.com' }, { id: 44, firstName: 'Dianna', lastName: 'Gislason-Lesch', email: 'Dianna88@hotmail.com' }, { id: 45, firstName: 'Reginald', lastName: 'Hagenes', email: 'Reginald_Hagenes51@gmail.com' }, { id: 46, firstName: 'Shelia', lastName: 'Turcotte', email: 'Shelia68@yahoo.com' }, { id: 47, firstName: 'Carlton', lastName: 'Jenkins', email: 'Carlton_Jenkins62@gmail.com' }, { id: 48, firstName: 'Lance', lastName: 'Wiegand', email: 'Lance_Wiegand@gmail.com' }, { id: 49, firstName: 'Ruby', lastName: 'Graham', email: 'Ruby20@hotmail.com' }, { id: 50, firstName: 'Hattie', lastName: 'Collier', email: 'Hattie60@hotmail.com' }, { id: 51, firstName: 'Viola', lastName: 'Rath', email: 'Viola_Rath6@gmail.com' }, { id: 52, firstName: 'Roland', lastName: 'Huel', email: 'Roland_Huel@yahoo.com' }, { id: 53, firstName: 'Leticia', lastName: 'Wiegand', email: 'Leticia65@hotmail.com' }, { id: 54, firstName: 'Jacqueline', lastName: 'Kulas', email: 'Jacqueline.Kulas@hotmail.com' }, { id: 55, firstName: 'Cristina', lastName: 'Jaskolski', email: 'Cristina.Jaskolski@hotmail.com' }, { id: 56, firstName: 'Felipe', lastName: 'Daugherty', email: 'Felipe_Daugherty@hotmail.com' }, { id: 57, firstName: 'Timothy', lastName: 'Heaney', email: 'Timothy.Heaney@gmail.com' }, { id: 58, firstName: 'Alonzo', lastName: 'Kutch', email: 'Alonzo12@yahoo.com' }, { id: 59, firstName: 'Keith', lastName: 'Kling', email: 'Keith25@yahoo.com' }, { id: 60, firstName: 'Janice', lastName: 'Goyette', email: 'Janice93@gmail.com' }, { id: 61, firstName: 'Helen', lastName: 'Kunze-MacGyver', email: 'Helen_Kunze-MacGyver@gmail.com' }, { id: 62, firstName: 'Barry', lastName: 'Jast', email: 'Barry.Jast@yahoo.com' }, { id: 63, firstName: 'Ramiro', lastName: 'Cummings', email: 'Ramiro.Cummings30@hotmail.com' }, { id: 64, firstName: 'Antonio', lastName: 'Little-Bahringer', email: 'Antonio.Little-Bahringer@gmail.com' }, { id: 65, firstName: 'Samuel', lastName: 'Zemlak', email: 'Samuel_Zemlak@gmail.com' }, { id: 66, firstName: 'Doris', lastName: 'Emard', email: 'Doris_Emard8@gmail.com' }, { id: 67, firstName: 'Olivia', lastName: 'Abernathy', email: 'Olivia_Abernathy@yahoo.com' }, { id: 68, firstName: 'Justin', lastName: 'Kohler', email: 'Justin_Kohler42@hotmail.com' }, { id: 69, firstName: 'Scott', lastName: 'Oberbrunner', email: 'Scott.Oberbrunner57@hotmail.com' }, { id: 70, firstName: 'Yolanda', lastName: 'Spinka', email: 'Yolanda.Spinka76@hotmail.com' }, { id: 71, firstName: 'Brad', lastName: 'Ullrich-Orn', email: 'Brad30@yahoo.com' }, { id: 72, firstName: 'Gloria', lastName: 'Fisher', email: 'Gloria.Fisher22@gmail.com' }, { id: 73, firstName: 'Sergio', lastName: 'Crist', email: 'Sergio_Crist93@gmail.com' }, { id: 74, firstName: 'Theresa', lastName: 'Sporer', email: 'Theresa.Sporer85@hotmail.com' }, { id: 75, firstName: 'Theodore', lastName: 'Wiegand', email: 'Theodore58@yahoo.com' }, { id: 76, firstName: 'Rudy', lastName: 'Rowe', email: 'Rudy_Rowe25@gmail.com' }, { id: 77, firstName: 'Kurt', lastName: 'Raynor', email: 'Kurt.Raynor@hotmail.com' }, { id: 78, firstName: 'Ruth', lastName: 'Medhurst', email: 'Ruth.Medhurst97@yahoo.com' }, { id: 79, firstName: 'Tim', lastName: 'Abernathy', email: 'Tim0@yahoo.com' }, { id: 80, firstName: 'Rebecca', lastName: 'Runolfsdottir', email: 'Rebecca.Runolfsdottir41@gmail.com' }, { id: 81, firstName: 'Angel', lastName: 'Aufderhar', email: 'Angel.Aufderhar19@yahoo.com' }, { id: 82, firstName: 'Javier', lastName: 'Bergstrom', email: 'Javier12@yahoo.com' }, { id: 83, firstName: 'Leigh', lastName: 'Klocko', email: 'Leigh.Klocko77@hotmail.com' }, { id: 84, firstName: 'Taylor', lastName: 'Rice', email: 'Taylor30@yahoo.com' }, { id: 85, firstName: 'Cindy', lastName: 'Goldner', email: 'Cindy_Goldner47@yahoo.com' }, { id: 86, firstName: 'Shannon', lastName: 'Crist', email: 'Shannon88@hotmail.com' }, { id: 87, firstName: 'Sarah', lastName: 'Maggio', email: 'Sarah54@hotmail.com' }, { id: 88, firstName: 'Carlton', lastName: 'Langosh-Glover', email: 'Carlton.Langosh-Glover@gmail.com' }, { id: 89, firstName: 'Felicia', lastName: 'Roob', email: 'Felicia_Roob65@yahoo.com' }, { id: 90, firstName: 'Simon', lastName: 'Kuhic', email: 'Simon30@yahoo.com' }, { id: 91, firstName: 'Sharon', lastName: 'Daniel', email: 'Sharon.Daniel2@hotmail.com' }, { id: 92, firstName: 'Erin', lastName: 'Bayer', email: 'Erin4@hotmail.com' }, { id: 93, firstName: 'Erika', lastName: 'Powlowski-Corwin', email: 'Erika33@gmail.com' }, { id: 94, firstName: 'Vicky', lastName: 'Pollich', email: 'Vicky_Pollich18@hotmail.com' }, { id: 95, firstName: 'Felicia', lastName: 'Ziemann', email: 'Felicia.Ziemann56@gmail.com' }, { id: 96, firstName: 'Colleen', lastName: 'Crooks', email: 'Colleen84@hotmail.com' }, { id: 97, firstName: 'Jimmy', lastName: 'Fisher', email: 'Jimmy7@yahoo.com' }, { id: 98, lastName: 'Reichert', firstName: 'Lula', email: 'Lula.Reichert48@gmail.com' }, { id: 99, firstName: 'Bethany', lastName: 'Schinner', email: 'Bethany.Schinner@yahoo.com' }, { id: 100, firstName: 'Allen', lastName: 'Hackett', email: 'Allen44@hotmail.com' }, ]; const totalRecords = 500; const recordsPerPage = 100; export function InfiniteScrolling() { const [records, setRecords] = useState(records.slice(0, recordsPerPage)); const [loading, setLoading] = useState(false); return ( Showing {records.length} records of {totalRecords} { if (loading || records.length >= totalRecords) return; setLoading(true); setTimeout(() => { const newRecords = records.concat(records.slice(0, recordsPerPage)); setRecords(newRecords); setLoading(false); notifications.show({ title: 'New records loaded', message: '', }); }, 1000); }} /> ); } ``` -------------------------------- ### Full-Featured DataTable with RTL Support Source: https://icflorescu.github.io/mantine-datatable/examples/rtl-support This example demonstrates a fully-featured DataTable with pinned columns, selection, sorting, pagination, and resizing, all configured to support RTL direction. It utilizes the DirectionProvider to manage the directionality of the table. ```javascript function RTLFullFeaturedExample({ direction }) { const [recordsPerPage, setRecordsPerPage] = useState(PAGE_SIZES[0]); const [selectedRecords, setSelectedRecords] = useState([]); const [sortStatus, setSortStatus] = useState>({ columnAccessor: 'firstName', direction: 'asc', }); const sortedRecords = useMemo(() => { const sorted = [...employees].sort((a, b) => { const accessor = sortStatus.columnAccessor as keyof Employee; const aValue = a[accessor]; const bValue = b[accessor]; if (typeof aValue === 'string' && typeof bValue === 'string') { return sortStatus.direction === 'asc' ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); } return 0; }); return sorted; }, [sortStatus]); const paginatedRecords = useMemo(() => { const start = (page - 1) * recordsPerPage; return sortedRecords.slice(start, start + recordsPerPage); }, [sortedRecords, page, recordsPerPage]); return ( ( ), }, ]} records={paginatedRecords} totalRecords={employees.length} recordsPerPage={recordsPerPage} onRecordsPerPageChange={setRecordsPerPage} recordsPerPageOptions={PAGE_SIZES} page={page} onPageChange={setPage} sortStatus={sortStatus} onSortStatusChange={setSortStatus} selectedRecords={selectedRecords} onSelectedRecordsChange={setSelectedRecords} /> ); } ``` -------------------------------- ### RTL Support Example Component Source: https://icflorescu.github.io/mantine-datatable/examples/rtl-support This component allows toggling between Left-to-Right (LTR) and Right-to-Left (RTL) text directions for various DataTable examples. It uses a SegmentedControl to switch the direction. ```javascript // Main example component with direction toggle export function RTLSupportExample() { const [direction, setDirection] = useState<'ltr' | 'rtl'>('ltr'); return ( Direction: setDirection(value as 'ltr' | 'rtl')} data={[ { label: 'LTR (Left to Right)', value: 'ltr' }, { label: 'RTL (Right to Left)', value: 'rtl' }, ]} /> Basic table: Column dragging: Full-featured: pinned columns, selection, sorting, pagination, resizing: ); } ``` -------------------------------- ### Basic RTL Table Example Source: https://icflorescu.github.io/mantine-datatable/examples/rtl-support Demonstrates a basic Mantine DataTable with RTL support. This snippet is suitable for simple data display where only text direction needs to be managed. ```tsx "use client"; import { DataTable, type DataTableSortStatus, useDataTableColumns } from 'mantine-datatable'; import { ActionIcon, Box, Button, DirectionProvider, Group, SegmentedControl, Stack, Text } from '@mantine/core'; import { IconColumns3, IconEdit, IconEye, IconTrash } from '@tabler/icons-react'; import clsx from 'clsx'; import { useMemo, useState } from 'react'; import { companies, type Employee, employees } from '~/data'; import classes from './RTLSupportExample.module.css'; // Example 1: Basic table without pinned columns export function RTLBasicExample({ direction }: { direction: 'ltr' | 'rtl' }) { return ( ); } ```