Row Expansion Customization
Expand rows to display custom content below each row. This demo renders a sub-component that shows the full row data as formatted JSON when a row is expanded.
Username | Account Status | Role | Avg Session Duration | Company Name | Last Visited At | Visit Count |
|---|
import {Fragment, useMemo} from "react"
import {
type ColumnDef,
getCoreRowModel,
getExpandedRowModel,
type Row,
} from "@qualcomm-ui/core/table"
import {Button} from "@qualcomm-ui/react/button"
import {ProgressRing} from "@qualcomm-ui/react/progress-ring"
import {flexRender, Table, useReactTable} from "@qualcomm-ui/react/table"
import {CodeHighlight} from "@qualcomm-ui/react-mdx/code-highlight"
import {type User, useUserData} from "./use-data"
const renderSubComponent = ({row}: {row: Row<User>}) => {
return (
<CodeHighlight
className="w-fit"
code={JSON.stringify(row.original, null, 2)}
disableCopy
language="json"
preProps={{style: {background: "transparent"}}}
/>
)
}
export function SubComponentsDemo() {
const {data = [], isFetching, refetch} = useUserData(10)
// always memoize your data and columns
const columns: ColumnDef<User>[] = useMemo(
() => [
{
cell: ({row}) => {
return !row.getCanExpand() ? (
""
) : (
<div className="inline-flex items-center justify-center">
<Table.RowExpandButton row={row} />
</div>
)
},
header: () => null,
id: "expander",
minSize: 52,
},
{
accessorKey: "username",
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: "Username",
},
{
accessorKey: "accountStatus",
header: "Account Status",
id: "accountStatus",
},
{
accessorKey: "role",
header: "Role",
id: "role",
size: 120,
},
{
accessorKey: "averageSessionDuration",
header: "Avg Session Duration",
id: "averageSessionDuration",
},
{
accessorKey: "companyName",
header: "Company Name",
id: "companyName",
minSize: 200,
},
{
accessorKey: "lastVisitedAt",
header: "Last Visited At",
id: "lastVisitedAt",
minSize: 205,
},
{
accessorKey: "visitCount",
header: "Visit Count",
id: "visitCount",
},
],
[],
)
const refreshData = () => refetch()
const table = useReactTable<User>({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
getRowCanExpand: () => true,
})
return (
<Table.Root>
<Table.ActionBar>
<Button onClick={() => void refreshData()} variant="outline">
Refresh Data
</Button>
{isFetching ? <ProgressRing size="xs" /> : null}
</Table.ActionBar>
<Table.ScrollContainer>
<Table.Table>
<Table.Header>
{table.getHeaderGroups().map((headerGroup) => (
<Table.Row key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<Table.HeaderCell
key={header.id}
colSpan={header.colSpan}
style={{minWidth: header.column.columnDef.minSize}}
>
{header.isPlaceholder ? null : (
<div>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</div>
)}
</Table.HeaderCell>
)
})}
</Table.Row>
))}
</Table.Header>
<Table.Body>
{table.getRowModel().rows.map((row) => {
return (
<Fragment key={row.id}>
<Table.Row>
{/* first row is a normal row */}
{row.getVisibleCells().map((cell) => {
return (
<Table.Cell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Table.Cell>
)
})}
</Table.Row>
{row.getIsExpanded() && (
<Table.Row>
{/* Expanded row contains a single cell that
spans the entire length of the table */}
<Table.Cell colSpan={row.getVisibleCells().length}>
{renderSubComponent({row})}
</Table.Cell>
</Table.Row>
)}
</Fragment>
)
})}
</Table.Body>
</Table.Table>
</Table.ScrollContainer>
</Table.Root>
)
}