QUI React Table

Grouping

First Name
Last Name
Age
Visits
Status
Profile Progress
Show
10
{
"grouping": []
}
import {useState} from "react"
import {ChevronDown, ChevronRight, Combine, Ungroup} from "lucide-react"
import {CodeHighlight} from "@qui/mdx-docs"
import {QButton, QIconButton, QPagination, QProgressCircle} from "@qui/react"
import {
ColumnDef,
flexRender,
getCoreRowModel,
getExpandedRowModel,
getFilteredRowModel,
getGroupedRowModel,
getPaginationRowModel,
GroupingState,
QTable,
QTbody,
QTd,
QTh,
QThead,
QTr,
useReactTable,
useTablePagination,
} from "@qui/react-table"
import {Person, usePersonData} from "~utils/data"
const columns: ColumnDef<Person>[] = [
{
accessorKey: "firstName",
cell: (info) => info.getValue(),
/**
* override the value used for row grouping
* (otherwise, defaults to the value derived from accessorKey /
* accessorFn)
*/
getGroupingValue: (row) => `${row.firstName} ${row.lastName}`,
header: "First Name",
},
{
accessorFn: (row) => row.lastName,
cell: (info) => info.getValue(),
header: "Last Name",
id: "lastName",
},
{
accessorKey: "age",
aggregatedCell: ({getValue}) => Math.round(getValue<number>() * 100) / 100,
aggregationFn: "median",
header: "Age",
},
{
accessorKey: "visits",
aggregationFn: "sum",
header: "Visits",
},
{
accessorKey: "status",
header: "Status",
},
{
accessorKey: "progress",
aggregatedCell: ({getValue}) =>
`${Math.round(getValue<number>() * 100) / 100}%`,
aggregationFn: "mean",
cell: ({getValue}) => `${Math.round(getValue<number>() * 100) / 100}%`,
header: "Profile Progress",
},
]
export default function Grouping() {
const {data = [], isFetching, refetch} = usePersonData(10000)
const refreshData = () => refetch()
const [grouping, setGrouping] = useState<GroupingState>([])
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getGroupedRowModel: data.length ? getGroupedRowModel() : undefined,
getPaginationRowModel: getPaginationRowModel(),
onGroupingChange: setGrouping,
state: {
grouping,
},
})
const paginationProps = useTablePagination(table)
return (
<div className="p-2">
<div className="mb-3 flex items-center gap-2">
<QButton onClick={refreshData} variant="outline">
Refresh Data
</QButton>
{isFetching ? <QProgressCircle size="xs" /> : null}
</div>
<QTable>
<QThead>
{table.getHeaderGroups().map((headerGroup) => (
<QTr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<QTh
key={header.id}
colSpan={header.colSpan}
style={{width: header.getSize()}}
>
{header.isPlaceholder ? null : (
<div className="flex items-center gap-1">
{header.column.getCanGroup() ? (
// If the header can be grouped, let's add a toggle
<QIconButton
dense
icon={
header.column.getIsGrouped() ? Ungroup : Combine
}
onClick={header.column.getToggleGroupingHandler()}
size="m"
title={
header.column.getIsGrouped() ? "Ungroup" : "Group"
}
/>
) : null}{" "}
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</div>
)}
</QTh>
)
})}
</QTr>
))}
</QThead>
<QTbody>
{table.getRowModel().rows.map((row) => {
return (
<QTr key={row.id}>
{row.getVisibleCells().map((cell) => {
return (
<QTd
key={cell.id}
isAggregated={cell.getIsAggregated()}
isGrouped={cell.getIsGrouped()}
>
{cell.getIsGrouped() ? (
// If it's a grouped cell, add an expander and row count
<div className="inline-flex items-center gap-2">
{row.getCanExpand() ? (
<QIconButton
icon={
row.getIsExpanded() ? ChevronDown : ChevronRight
}
onClick={row.getToggleExpandedHandler()}
size="s"
/>
) : null}
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}{" "}
({row.subRows.length})
</div>
) : cell.getIsAggregated() ? (
// If the cell is aggregated, use the Aggregated
// renderer for cell
flexRender(
cell.column.columnDef.aggregatedCell ??
cell.column.columnDef.cell,
cell.getContext(),
)
) : cell.getIsPlaceholder() ? null : ( // For cells with repeated values, render null
// Otherwise, just render the regular cell
flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)
)}
</QTd>
)
})}
</QTr>
)
})}
</QTbody>
</QTable>
<div className="mt-4">
<QPagination
{...paginationProps}
renderPageMeta={(context) =>
`${context.currentPage} of ${context.totalPages}`
}
rowsPerPageLabel="Show"
rowsPerPageOptions={[10, 20, 50]}
/>
</div>
<CodeHighlight
className="mt-4 w-fit"
code={JSON.stringify({grouping}, null, 2)}
disableCopy
language="json"
/>
</div>
)
}