Column Ordering (Drag & Drop)

This example features drag and drop column reordering using the Pragmatic Drag and Drop library.

Username
Account Status
Role
Avg Session Duration
Company Name
Last Visited At
Visit Count
{
"columnOrder": [
"username",
"accountStatus",
"role",
"averageSessionDuration",
"companyName",
"lastVisitedAt",
"visitCount"
]
}
import {useMemo, useState} from "react"

import {
  type ColumnDef,
  type ColumnOrderState,
  getCoreRowModel,
} 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 {DraggableColumnHeader} from "./draggable-column-header"
import {type User, useUserData} from "./use-data"

export function ColumnDndDemo() {
  const {data = [], isFetching, refetch} = useUserData(10)

  // always memoize your data and columns
  const userColumns: ColumnDef<User>[] = useMemo(
    () => [
      {
        accessorKey: "username",
        header: "Username",
        id: "username",
      },
      {
        accessorKey: "accountStatus",
        header: "Account Status",
        id: "accountStatus",
      },
      {
        accessorKey: "role",
        header: "Role",
        id: "role",
        minSize: 180,
      },
      {
        accessorKey: "averageSessionDuration",
        header: "Avg Session Duration",
        id: "averageSessionDuration",
      },
      {
        accessorKey: "companyName",
        header: "Company Name",
        id: "companyName",
        minSize: 220,
      },
      {
        accessorKey: "lastVisitedAt",
        header: "Last Visited At",
        id: "lastVisitedAt",
        minSize: 205,
      },
      {
        accessorKey: "visitCount",
        header: "Visit Count",
        id: "visitCount",
      },
    ],
    [],
  )

  const [columnOrder, setColumnOrder] = useState<ColumnOrderState>(
    userColumns.map((column) => column.id as string), // must start out with populated columnOrder so we can splice
  )

  const regenerateData = () => refetch()

  const resetOrder = () =>
    setColumnOrder(userColumns.map((column) => column.id as string))

  const table = useReactTable({
    columns: userColumns,
    data,
    getCoreRowModel: getCoreRowModel(),
    onColumnOrderChange: setColumnOrder,
    state: {
      columnOrder,
    },
  })

  return (
    <div className="flex w-full flex-col gap-4 p-2">
      <Table.Root>
        <Table.ActionBar>
          <Button onClick={() => void regenerateData()} variant="outline">
            Regenerate
          </Button>
          <Button onClick={resetOrder} variant="outline">
            Reset Order
          </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) => (
                    <DraggableColumnHeader
                      key={header.id}
                      header={header}
                      table={table}
                    />
                  ))}
                </Table.Row>
              ))}
            </Table.Header>
            <Table.Body>
              {table.getRowModel().rows.map((row) => (
                <Table.Row key={row.id}>
                  {row.getVisibleCells().map((cell) => (
                    <Table.Cell
                      key={cell.id}
                      style={{minWidth: cell.column.columnDef.minSize}}
                    >
                      {flexRender(
                        cell.column.columnDef.cell,
                        cell.getContext(),
                      )}
                    </Table.Cell>
                  ))}
                </Table.Row>
              ))}
            </Table.Body>
          </Table.Table>
        </Table.ScrollContainer>
      </Table.Root>

      <CodeHighlight
        className="w-fit"
        code={JSON.stringify(
          {columnOrder: table.getState().columnOrder},
          null,
          2,
        )}
        disableCopy
        language="json"
      />
    </div>
  )
}