QUI React Table

Row Expansion Customization

Name
Info
First Name
Last Name
Age
Visits
Status
Profile Progress
import {Fragment} from "react"
import {ChevronRightIcon} from "lucide-react"
import {clsx} from "@qui/base"
import {CodeHighlight} from "@qui/mdx-docs"
import {QButton, QIconButton, QProgressCircle} from "@qui/react"
import {
ColumnDef,
flexRender,
getCoreRowModel,
getExpandedRowModel,
QTable,
QTbody,
QTd,
QTh,
QThead,
QTr,
Row,
useReactTable,
} from "@qui/react-table"
import {Person, usePersonData} from "~utils/data"
const columns: ColumnDef<Person>[] = [
{
columns: [
{
cell: ({row}) => {
return row.getCanExpand() ? (
<div className="inline-flex items-center justify-center">
<QIconButton
className="inline-flex justify-center"
icon={
<ChevronRightIcon
size={16}
style={{
transform: row.getIsExpanded()
? "rotate(90deg)"
: "unset",
transition: "transform 161ms ease",
}}
/>
}
onClick={row.getToggleExpandedHandler()}
style={{
height: "100%",
width: "100%",
}}
/>
</div>
) : (
""
)
},
header: () => null,
id: "expander",
maxSize: 38,
},
{
accessorKey: "firstName",
cell: ({getValue, row}) => (
<div
style={{
// Since rows are flattened by default,
// we can use the row.depth property
// and paddingLeft to visually indicate the depth
// of the row
paddingLeft: `${row.depth * 2}rem`,
}}
>
{getValue<string>()}
</div>
),
header: "First Name",
},
{
accessorFn: (row) => row.lastName,
cell: (info) => info.getValue(),
header: "Last Name",
id: "lastName",
},
],
header: "Name",
},
{
columns: [
{
accessorKey: "age",
header: "Age",
},
{
accessorKey: "visits",
header: "Visits",
},
{
accessorKey: "status",
header: "Status",
},
{
accessorKey: "progress",
header: "Profile Progress",
},
],
header: "Info",
},
]
const renderSubComponent = ({row}: {row: Row<Person>}) => {
return (
<CodeHighlight
className="w-fit"
code={JSON.stringify(row.original, null, 2)}
disableCopy
language="json"
preProps={{style: {background: "transparent"}}}
/>
)
}
export default function SubComponents() {
const {data = [], isFetching, refetch} = usePersonData(20)
const refreshData = () => refetch()
const table = useReactTable<Person>({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
getRowCanExpand: () => true,
})
return (
<div className="overflow-x-auto 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>
<div className="overflow-x-auto">
<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>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</div>
)}
</QTh>
)
})}
</QTr>
))}
</QThead>
<QTbody>
{table.getRowModel().rows.map((row) => {
return (
<Fragment key={row.id}>
<QTr>
{/* first row is a normal row */}
{row.getVisibleCells().map((cell) => {
return (
<QTd
key={cell.id}
className={clsx({
// disable padding for the expander cell
"p-0": cell.column.id === "expander",
})}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</QTd>
)
})}
</QTr>
{row.getIsExpanded() && (
<QTr>
{/* 2nd row is a custom 1 cell row */}
<QTd colSpan={row.getVisibleCells().length}>
{renderSubComponent({row})}
</QTd>
</QTr>
)}
</Fragment>
)
})}
</QTbody>
</QTable>
</div>
</div>
)
}