Skip to main content

Data Tables

Maybern uses AG-Grid for complex data tables with features like sorting, filtering, grouping, and export.

Basic Table

import { AgGridReact } from "ag-grid-react";

function MyTable() {
  const columnDefs = [
    { field: "name", headerName: "Name" },
    { field: "status", headerName: "Status" },
    { field: "amount", headerName: "Amount" },
  ];
  
  return (
    <AgGridReact
      columnDefs={columnDefs}
      rowData={data}
      defaultColDef={{
        sortable: true,
        filter: true,
        resizable: true,
      }}
    />
  );
}

Column Configuration

Basic Columns

const columnDefs = [
  { field: "name", headerName: "Name", flex: 1 },
  { field: "status", width: 120 },
  { field: "createdAt", headerName: "Created", type: "dateColumn" },
];

Column Types

const columnDefs = [
  // Money column
  {
    field: "amount",
    headerName: "Amount",
    type: "numericColumn",
    valueFormatter: ({ value }) => formatMoney(value),
  },
  
  // Date column
  {
    field: "date",
    headerName: "Date",
    valueFormatter: ({ value }) => formatDate(value),
  },
  
  // Percentage column
  {
    field: "rate",
    headerName: "Rate",
    valueFormatter: ({ value }) => `${(value * 100).toFixed(2)}%`,
  },
];

Custom Cell Renderers

const StatusCellRenderer = ({ value }) => (
  <Badge colorScheme={value === "active" ? "green" : "gray"}>
    {value}
  </Badge>
);

const columnDefs = [
  {
    field: "status",
    cellRenderer: StatusCellRenderer,
  },
  {
    field: "actions",
    cellRenderer: ActionsCellRenderer,
    cellRendererParams: {
      onEdit: handleEdit,
      onDelete: handleDelete,
    },
  },
];

Features

Sorting

<AgGridReact
  defaultColDef={{
    sortable: true,
  }}
  // Initial sort
  initialState={{
    sort: {
      sortModel: [{ colId: "name", sort: "asc" }],
    },
  }}
/>

Filtering

const columnDefs = [
  {
    field: "name",
    filter: "agTextColumnFilter",
    filterParams: {
      filterOptions: ["contains", "startsWith"],
    },
  },
  {
    field: "status",
    filter: "agSetColumnFilter",
    filterParams: {
      values: ["active", "inactive", "pending"],
    },
  },
];

Pagination

<AgGridReact
  pagination={true}
  paginationPageSize={25}
  paginationPageSizeSelector={[10, 25, 50, 100]}
/>

Row Selection

<AgGridReact
  rowSelection="multiple"
  onSelectionChanged={handleSelectionChanged}
  isRowSelectable={(node) => node.data.status !== "locked"}
/>

Export

const gridRef = useRef<AgGridReact>(null);

const handleExport = () => {
  gridRef.current?.api.exportDataAsCsv({
    fileName: "export.csv",
  });
};

<AgGridReact ref={gridRef} />

Server-Side Data

Pagination

function ServerSideTable() {
  const [page, setPage] = useState(1);
  const { data } = useTransactionList({ page, pageSize: 25 });
  
  return (
    <AgGridReact
      rowData={data?.results}
      pagination={true}
      paginationPageSize={25}
      onPaginationChanged={(e) => {
        const newPage = e.api.paginationGetCurrentPage() + 1;
        setPage(newPage);
      }}
    />
  );
}

Infinite Scroll

<AgGridReact
  rowModelType="infinite"
  datasource={{
    getRows: async (params) => {
      const { startRow, endRow } = params;
      const data = await fetchData({ offset: startRow, limit: endRow - startRow });
      params.successCallback(data.results, data.total);
    },
  }}
/>

Common Patterns

Row Click Handler

<AgGridReact
  onRowClicked={({ data }) => {
    navigate(routes.detail({ id: data.id }));
  }}
  rowStyle={{ cursor: "pointer" }}
/>

Loading State

<AgGridReact
  rowData={isLoading ? null : data}
  overlayLoadingTemplate="<span>Loading...</span>"
  overlayNoRowsTemplate="<span>No data</span>"
/>

Editable Cells

const columnDefs = [
  {
    field: "name",
    editable: true,
    cellEditor: "agTextCellEditor",
  },
  {
    field: "amount",
    editable: true,
    cellEditor: "agNumberCellEditor",
  },
];

<AgGridReact
  columnDefs={columnDefs}
  onCellValueChanged={({ data, colDef, newValue }) => {
    handleUpdate(data.id, colDef.field, newValue);
  }}
/>

Styling

<AgGridReact
  className="ag-theme-quartz"
  domLayout="autoHeight"
  rowHeight={48}
  headerHeight={40}
/>