---
title: "Row Pinning"
framework: react
version: "36.1.0"
---

# Row Pinning

Pinned rows appear either above or below the normal rows of a table. This is sometimes also known as **Frozen Rows** or **Floating Rows**. Rows can be pinned via the [Context Menu](https://www.ag-grid.com/react-data-grid/context-menu/) or Grid Options.

## Enabling Row Pinning

To enable row pinning, set `enableRowPinning` to `true`. To restrict pinning to only one direction, set it to `'top'` or `'bottom'`.

```jsx
const enableRowPinning = true;

<AgGridReact enableRowPinning={enableRowPinning} />
```

## Pinning Rows on First Render

To have a row appear as pinned when the grid initially renders data, use the `isRowPinned` callback. Returning `'top'` or `'bottom'` from this callback will pin the row to the top or bottom respectively, and returning `null` or `undefined` will leave the row unpinned. As an example, the snippet below will pin all rows whose `country` field is `null` in the top container, and all the other rows will be unpinned.

```jsx
const enableRowPinning = true;
const isRowPinned = (rowNode) => {
    return rowNode.data?.country == null ? 'top' : null;
};

<AgGridReact
    enableRowPinning={enableRowPinning}
    isRowPinned={isRowPinned}
/>
```

This is illustrated in the example below. Rows that are pinned appear fixed at the top (or bottom) of the grid, as well as remaining in the main viewport. Pinned rows are styled bold by default to visually distinguish them.

#### Pinning on First Render

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  IsRowPinned,
  ModuleRegistry,
  PinnedRowModule,
  Theme,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { ContextMenuModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [ClientSideRowModelModule, ContextMenuModule, PinnedRowModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const isRowPinned = useCallback((rowNode) => {
    return rowNode.data?.country == null ? "top" : null;
  }, []);
  const theme = useMemo<Theme | "legacy">(() => {
    return themeQuartz.withParams({
      pinnedRowBorder: {
        width: 2,
      },
    });
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/small-olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            enableRowPinning={true}
            isRowPinned={isRowPinned}
            theme={theme}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Pinning on First Render](https://www.ag-grid.com/examples/row-pinning/pinning-on-render/reactFunctionalTs)

Note that all the examples on this page also apply additional styling to visually separate the pinned rows from the rows in the main viewport.

```jsx
const theme = themeQuartz.withParams({
    pinnedRowBorder: {
        width: 2
    },
});

<AgGridReact theme={theme} />
```

To see what other parameters are available for the theming of pinned rows, see the [Theme Builder](https://www.ag-grid.com/theme-builder/).

## Pinning Rows via the Context Menu

> **Note**
>
> This approach requires the [Context Menu](https://www.ag-grid.com/react-data-grid/context-menu/) which is an Enterprise feature.

To pin a row, use right-click to bring up the [Context Menu](https://www.ag-grid.com/react-data-grid/context-menu/) and select one of the options in the "Pin Row" submenu. In the example below, try the following:

1. Pin a row to the top.
2. Switch the row to being pinned to the bottom.
3. Unpin the row.

#### Simple Row Pinning

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  PinnedRowModule,
  Theme,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { ContextMenuModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [PinnedRowModule, ClientSideRowModelModule, ContextMenuModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const theme = useMemo<Theme | "legacy">(() => {
    return themeQuartz.withParams({
      pinnedRowBorder: {
        width: 2,
      },
    });
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/small-olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            enableRowPinning={true}
            theme={theme}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Simple Row Pinning](https://www.ag-grid.com/examples/row-pinning/simple-pinning/reactFunctionalTs)

## Preventing Rows from being Pinnable

To prevent a user from pinning a row via the context menu, use the `isRowPinnable` callback. As an example, the snippet below will prevent any rows being pinned where the `sport` field is `'Swimming'`.

```jsx
const enableRowPinning = true;
const isRowPinnable = (rowNode) => {
    return rowNode.data?.sport != 'Swimming';
};

<AgGridReact
    enableRowPinning={enableRowPinning}
    isRowPinnable={isRowPinnable}
/>
```

This is illustrated in the example below. Note that the "Pin Rows" submenu does not appear in the context menu for rows whose `sport` field is `'Swimming'`.

#### Prevent Rows from being Pinnable

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  IsRowPinnable,
  ModuleRegistry,
  PinnedRowModule,
  Theme,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { ClipboardModule, ContextMenuModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  PinnedRowModule,
  ClientSideRowModelModule,
  ContextMenuModule,
  ClipboardModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const isRowPinnable = useCallback((rowNode) => {
    return rowNode.data?.sport != "Swimming";
  }, []);
  const theme = useMemo<Theme | "legacy">(() => {
    return themeQuartz.withParams({
      pinnedRowBorder: {
        width: 2,
      },
    });
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/small-olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            enableRowPinning={true}
            isRowPinnable={isRowPinnable}
            theme={theme}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Prevent Rows from being Pinnable](https://www.ag-grid.com/examples/row-pinning/prevent-pinning/reactFunctionalTs)

## Sorting and Filtering Pinned Rows

When sorts and filters are applied to the grid, they will also be applied to pinned rows.

#### Sorting and Filtering Pinned Rows

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  IsRowPinned,
  ModuleRegistry,
  PinnedRowModule,
  Theme,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { ContextMenuModule, SetFilterModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  PinnedRowModule,
  ClientSideRowModelModule,
  ContextMenuModule,
  SetFilterModule,
  ColumnApiModule,
];

function filterSwimming(api: GridApi<IOlympicData>) {
  api
    .setColumnFilterModel("sport", { values: ["Swimming"] })
    .then(() => api.onFilterChanged());
}

function sortGold(api: GridApi<IOlympicData>) {
  api.applyColumnState({ state: [{ colId: "gold", sort: "desc" }] });
}

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<IOlympicData[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport", filter: true, floatingFilter: true },
    { field: "gold" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const isRowPinned = useCallback(
    (node) => (!node.data?.country ? "top" : null),
    [],
  );
  const theme = useMemo<Theme | "legacy">(() => {
    return themeQuartz.withParams({
      pinnedRowBorder: {
        width: 2,
      },
    });
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/small-olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: IOlympicData[]) => {
        setRowData(data);
        filterSwimming(params.api);
        sortGold(params.api);
      });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            enableRowPinning={true}
            isRowPinned={isRowPinned}
            theme={theme}
            onGridReady={onGridReady}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Sorting and Filtering Pinned Rows](https://www.ag-grid.com/examples/row-pinning/sorting-and-filtering/reactFunctionalTs)

## Selecting Pinned Rows

Pinned rows can be selected just as normal rows can be selected. The selection state of a pinned row will mirror the selection state of the original row.

#### Selecting Pinned Rows

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  IsRowPinned,
  ModuleRegistry,
  PinnedRowModule,
  RowApiModule,
  RowSelectionModule,
  RowSelectionOptions,
  Theme,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { ContextMenuModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  PinnedRowModule,
  RowSelectionModule,
  RowApiModule,
  ContextMenuModule,
];

const GridExample = () => {
  const gridRef = useRef<AgGridReact<IOlympicData>>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const isRowPinned = useCallback(
    (node) => (!node.data?.country ? "top" : null),
    [],
  );
  const rowSelection = useMemo<
    RowSelectionOptions | "single" | "multiple"
  >(() => {
    return {
      mode: "multiRow",
    };
  }, []);
  const theme = useMemo<Theme | "legacy">(() => {
    return themeQuartz.withParams({
      pinnedRowBorder: {
        width: 2,
      },
    });
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/small-olympic-winners.json",
  );

  const onFirstDataRendered = useCallback(() => {
    ["1", "3", "5"].forEach((id) => {
      gridRef.current!.api.getRowNode(id)?.setSelected(true);
    });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            ref={gridRef}
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            enableRowPinning={true}
            isRowPinned={isRowPinned}
            rowSelection={rowSelection}
            theme={theme}
            onFirstDataRendered={onFirstDataRendered}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Selecting Pinned Rows](https://www.ag-grid.com/examples/row-pinning/selecting-pinned/reactFunctionalTs)

## Pinning the Grand Total Row

The [Grand Total Rows](https://www.ag-grid.com/react-data-grid/aggregation-total-rows/#enabling-a-grand-total-row) can be pinned in three ways.

1. Setting the value of the `grandTotalRow` grid option to either `'pinnedTop'` or `'pinnedBottom'`.
2. Manually pin the grand total row via the context menu when `grandTotalRow` is either `'top'` or `'bottom'`.
3. Return `'top'` or `'bottom'` from the `isRowPinned` callback when it's called on the grand total row node.

#### Pinning Grand Total Row

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  PinnedRowModule,
  RowPinnedType,
  Theme,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { ContextMenuModule, RowGroupingModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  RowGroupingModule,
  ContextMenuModule,
  PinnedRowModule,
];

function getGrandTotalRow() {
  return document.querySelector<HTMLSelectElement>("#select-grand-total-row")
    ?.value as GridOptions["grandTotalRow"] | "isRowPinned";
}

function setGrandTotalRow(
  api: GridApi<IOlympicData>,
  value: GridOptions["grandTotalRow"],
) {
  api.setGridOption("grandTotalRow", value);
}

function setIsRowPinned(api: GridApi<IOlympicData>, value: RowPinnedType) {
  api.setGridOption("isRowPinned", (node) => {
    if (node.level === -1 && node.footer) {
      return value;
    }
  });
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact<IOlympicData>>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country", rowGroup: true, hide: true },
    { field: "sport" },
    { field: "gold", aggFunc: "sum" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      headerName: "Country",
    };
  }, []);
  const theme = useMemo<Theme | "legacy">(() => {
    return themeQuartz.withParams({
      pinnedRowBorder: {
        width: 2,
      },
    });
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/small-olympic-winners.json",
  );

  const onFirstDataRendered = useCallback(() => {
    const value = getGrandTotalRow();
    if (value === "isRowPinned") {
      setGrandTotalRow(gridRef.current!.api, "bottom");
      setIsRowPinned(gridRef.current!.api, "top");
    } else {
      setGrandTotalRow(gridRef.current!.api, value);
    }
  }, []);

  const update = useCallback(() => {
    const value = getGrandTotalRow();
    if (value === "isRowPinned") {
      setGrandTotalRow(gridRef.current!.api, "bottom");
      setIsRowPinned(gridRef.current!.api, "top");
    } else {
      setGrandTotalRow(gridRef.current!.api, value);
    }
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <select id="select-grand-total-row" onChange={update}>
              <option value="pinnedBottom">pinnedBottom</option>
              <option value="pinnedTop">pinnedTop</option>
              <option value="bottom">bottom</option>
              <option value="top">top</option>
              <option value="isRowPinned">isRowPinned</option>
            </select>
          </div>

          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              ref={gridRef}
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              enableRowPinning={true}
              theme={theme}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Pinning Grand Total Row](https://www.ag-grid.com/examples/row-pinning/pinning-grand-total/reactFunctionalTs)

Note that when `grandTotalRow` is `'pinnedTop'` or `'pinnedBottom'` the user is not able to unpin the grand total row.

## Providing Pinned Row Data

> **Note**
>
> You cannot provide pinned row data at the same time as using `enableRowPinning` to manually pin rows.

Pinned row data may be provided directly to the grid via Grid Options. Providing pinned rows this way means they cannot be altered by end users.

#### Pinned Row Data

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  PinnedRowModule,
  Theme,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [PinnedRowModule, ClientSideRowModelModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);
  const theme = useMemo<Theme | "legacy">(() => {
    return themeQuartz.withParams({
      pinnedRowBackgroundColor:
        "color-mix(in srgb, var(--ag-background-color), #ffeb3b 18%)",
    });
  }, []);
  const pinnedTopRowData = useMemo<any[]>(() => {
    return [
      {
        athlete: "TOP (athlete)",
        country: "TOP (country)",
        sport: "TOP (sport)",
      },
    ];
  }, []);
  const pinnedBottomRowData = useMemo<any[]>(() => {
    return [
      {
        athlete: "BOTTOM (athlete)",
        country: "BOTTOM (country)",
        sport: "BOTTOM (sport)",
      },
    ];
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            theme={theme}
            pinnedTopRowData={pinnedTopRowData}
            pinnedBottomRowData={pinnedBottomRowData}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Pinned Row Data](https://www.ag-grid.com/examples/row-pinning/pinned-row-data/reactFunctionalTs)

Set Pinned Rows using grid attributes `pinnedTopRowData` and `pinnedBottomRowData`.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `pinnedTopRowData` | `any[]` |  |  | Data to be displayed as pinned top rows in the grid. Module: [`PinnedRowModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `pinnedBottomRowData` | `any[]` |  |  | Data to be displayed as pinned bottom rows in the grid. Module: [`PinnedRowModule`](https://www.ag-grid.com/react-data-grid/modules/). |

### Unsupported Features

When providing pinned row data directly via `pinnedTopRowData` and `pinnedBottomRowData`, the following are not possible:

- **Sorting**: Pinned rows cannot be sorted.
- **Filtering**: Pinned rows are not filtered.
- **Row Grouping**: Pinned rows cannot be grouped.
- **Row Selection**: Pinned rows cannot be selected.

## API Reference

> **Note**
>
> The pinned row state can be saved and restored as part of [Grid State](https://www.ag-grid.com/react-data-grid/grid-state/).

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `enableRowPinning` | `boolean \| 'top' \| 'bottom'` |  |  | Determines whether manual row pinning is enabled via the row context menu. Set to `true` to allow pinning rows to top or bottom. Set to `'top'` to allow pinning rows to the top only. Set to `'bottom'` to allow pinning rows to the bottom only. Module: [`PinnedRowModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `isRowPinnable` | `IsRowPinnable` |  |  | Return `true` if the grid should allow the row to be manually pinned. Return `false` if the grid should prevent the row from being pinned When not defined, all rows default to pinnable. Module: [`PinnedRowModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `isRowPinned` | `IsRowPinned` |  |  | Called for every row in the grid. Return "top", "bottom" if the row should be initially pinned to the top or bottom respectively. Return `null` or `undefined` otherwise. User interactions can subsequently still change the pinned state of a row. Module: [`PinnedRowModule`](https://www.ag-grid.com/react-data-grid/modules/). |

### Events

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `pinnedRowsChanged` | `PinnedRowsChangedEvent` |  |  | A row has been pinned to top or bottom, or unpinned. |
