MRT logoMaterial React Table

On This Page

    Row Pinning Feature Guide

    Material React Table has a powerful row pinning feature that allows you to either pin rows to the top and bottom of the table as a user scrolls, or pin rows to the top and bottom of the table regardless of scrolling.

    Relevant Table Options

    1
    boolean | (row: MRT_Row) => boolean
    MRT Row Selection Docs
    2
    boolean
    true
    3
    OnChangeFn<RowSelectionState>
    TanStack Table Pinning Docs
    4
    'sticky' | 'top' | 'bottom' | 'top-and-bottom' | 'select-sticky' | 'select-top' | 'select-bottom'
    'sticky'

    Relevant State

    1
    { top: string[], bottom: string[] }
    { top: [], bottom: [] }
    TanStack Table Column Pinning Docs

    Row Pinning Display Modes

    You can enable the row pinning feature with the enableRowPinning table option. There are multiple display modes that you can choose from with the rowPinningDisplayMode table option.

    const table = useMaterialReactTable({
    columns,
    data,
    enableRowPinning: true,
    rowPinningDisplayMode: 'sticky', // default
    });
    • sticky - This is the default display mode. It will make rows stick to the top and bottom of the table as a user scrolls.

    • top - This will statically pin rows to the top of the table upon pinning.

    • bottom - This will statically pin rows to the bottom of the table upon pinning.

    • top-and-bottom - This allows the user to statically pin rows to either the top or bottom of the table.

    • select-sticky - This pins selected rows to the top and bottom of the table as a user scrolls. (alternative pinning UI)

    • select-top - This statically pins selected rows to the top of the table upon pinning. (alternative pinning UI)

    • select-bottom - This statically pins selected rows to the bottom of the table upon pinning. (alternative pinning UI)

    Sticky Row Pinning

    By default, the row pinning feature will add a position sticky style to the pinned rows. This means that the pinned rows will stay in place if the row is already in view. However, the rows will stay in view as the user scrolls up or down.

    Sticky row pinning will work best if you give your rows a fixed height, or at least disable any kind of whitespace wrapping.

    const table = useMaterialReactTable({
    columns,
    data,
    enableRowPinning: true,
    muiTableBodyRowProps: ({ row, table }) => {
    const { density } = table.getState();
    return {
    sx: {
    //Set a fixed height for pinned rows
    height: row.getIsPinned()
    ? `${
    //Default mrt row height estimates. Adjust as needed.
    density === 'compact' ? 37 : density === 'comfortable' ? 53 : 69
    }px`
    : undefined,
    },
    };
    },
    rowPinningDisplayMode: 'sticky', // default
    });

    Demo

    Open StackblitzOpen Code SandboxOpen on GitHub
    DylanMurraydmurray@yopmail.comEast Daphne
    RaquelKohlerrkholer33@yopmail.comColumbus
    ErvinReingerereinger@mailinator.comSouth Linda
    BrittanyMcCulloughbmccullough44@mailinator.comLincoln
    BransonFramibframi@yopmain.comNew York
    BenMurraybenm@email.comSalt Lake City
    ElenaSmithesmith@yopmail.comLos Angeles
    MichaelJohnsonmjohnson@mailinator.comChicago
    SophiaBrownsbrown@yopmail.comHouston
    LucasDavisldavis@mailinator.comPhoenix
    OliviaGarciaogarcia@yopmail.comPhiladelphia
    LiamRodriguezlrodriguez@mailinator.comSan Antonio
    EmmaMartinezemartinez@yopmail.comSan Diego
    NoahHernandeznhernandez@mailinator.comDallas
    AvaLopezalopez@yopmail.comSan Jose
    WilliamGonzalezwgonzalez@mailinator.comAustin
    IsabellaWilsoniwilson@yopmail.comJacksonville
    JamesAndersonjanderson@mailinator.comFort Worth
    MiaThomasmthomas@yopmail.comColumbus
    AlexanderTaylorataylor@mailinator.comCharlotte
    GraceMooregmoore@yopmail.comIndianapolis
    EthanWhiteewhite@mailinator.comSan Francisco
    LilyHarrislharris@yopmail.comSeattle
    DanielMartindmartin@mailinator.comDenver
    ZoeJacksonzjackson@yopmail.comBoston
    MatthewThompsonmthompson@mailinator.comNashville
    EllaGarciaegarcia@yopmail.comDetroit
    DavidMartinezdmartinez@mailinator.comPortland
    AriaRobinsonarobinson@yopmail.comLas Vegas
    JosephClarkjclark@mailinator.comBaltimore

    Source Code

    1import { useMemo } from 'react';
    2import {
    3 MaterialReactTable,
    4 useMaterialReactTable,
    5 type MRT_ColumnDef,
    6} from 'material-react-table';
    7import { data, type Person } from './makeData';
    8
    9const Example = () => {
    10 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    11 () => [
    12 {
    13 accessorKey: 'firstName',
    14 header: 'First Name',
    15 },
    16 {
    17 accessorKey: 'lastName',
    18 header: 'Last Name',
    19 },
    20 {
    21 accessorKey: 'email',
    22 header: 'Email',
    23 },
    24 {
    25 accessorKey: 'city',
    26 header: 'City',
    27 },
    28 ],
    29 [],
    30 );
    31
    32 const table = useMaterialReactTable({
    33 columns,
    34 data,
    35 enableRowPinning: true,
    36 enablePagination: false,
    37 enableStickyHeader: true,
    38 getRowId: (row) => row.email,
    39 initialState: {
    40 rowPinning: {
    41 top: ['rkholer33@yopmail.com', 'egarcia@yopmail.com'],
    42 bottom: [],
    43 },
    44 },
    45 muiTableContainerProps: {
    46 sx: {
    47 maxHeight: '400px',
    48 },
    49 },
    50 muiTableBodyRowProps: ({ row, table }) => {
    51 const { density } = table.getState();
    52 return {
    53 sx: {
    54 //Set a fixed height for pinned rows
    55 height: row.getIsPinned()
    56 ? `${
    57 //Default mrt row height estimates. Adjust as needed.
    58 density === 'compact' ? 37 : density === 'comfortable' ? 53 : 69
    59 }px`
    60 : undefined,
    61 },
    62 };
    63 },
    64 });
    65
    66 return <MaterialReactTable table={table} />;
    67};
    68
    69export default Example;
    70

    Note: Sticky Row Pinning is not currently compatible with row virtualization.

    Static Row Pinning

    Some of the other row pinning modes will show pinned rows at the top or bottom of the the table regardless of scrolling. This is a simpler implementation of the row pinning feature.

    Static row pinning does not require set row heights, as they will render in a normal <tbody> element that itself is what is sticky.

    Demo

    DylanMurraydmurray@yopmail.comEast Daphne
    RaquelKohlerrkholer33@yopmail.comColumbus
    ErvinReingerereinger@mailinator.comSouth Linda
    BrittanyMcCulloughbmccullough44@mailinator.comLincoln
    BransonFramibframi@yopmain.comNew York
    BenMurraybenm@email.comSalt Lake City
    ElenaSmithesmith@yopmail.comLos Angeles
    MichaelJohnsonmjohnson@mailinator.comChicago
    SophiaBrownsbrown@yopmail.comHouston
    LucasDavisldavis@mailinator.comPhoenix
    OliviaGarciaogarcia@yopmail.comPhiladelphia
    LiamRodriguezlrodriguez@mailinator.comSan Antonio
    EmmaMartinezemartinez@yopmail.comSan Diego
    NoahHernandeznhernandez@mailinator.comDallas
    AvaLopezalopez@yopmail.comSan Jose
    WilliamGonzalezwgonzalez@mailinator.comAustin
    IsabellaWilsoniwilson@yopmail.comJacksonville
    JamesAndersonjanderson@mailinator.comFort Worth
    MiaThomasmthomas@yopmail.comColumbus
    AlexanderTaylorataylor@mailinator.comCharlotte
    GraceMooregmoore@yopmail.comIndianapolis
    EthanWhiteewhite@mailinator.comSan Francisco
    LilyHarrislharris@yopmail.comSeattle
    DanielMartindmartin@mailinator.comDenver
    ZoeJacksonzjackson@yopmail.comBoston
    MatthewThompsonmthompson@mailinator.comNashville
    EllaGarciaegarcia@yopmail.comDetroit
    DavidMartinezdmartinez@mailinator.comPortland
    AriaRobinsonarobinson@yopmail.comLas Vegas
    JosephClarkjclark@mailinator.comBaltimore

    Source Code

    1import { useMemo } from 'react';
    2import {
    3 MaterialReactTable,
    4 useMaterialReactTable,
    5 type MRT_ColumnDef,
    6} from 'material-react-table';
    7import { data, type Person } from './makeData';
    8
    9const Example = () => {
    10 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    11 () => [
    12 {
    13 accessorKey: 'firstName',
    14 header: 'First Name',
    15 },
    16 {
    17 accessorKey: 'lastName',
    18 header: 'Last Name',
    19 },
    20 {
    21 accessorKey: 'email',
    22 header: 'Email',
    23 },
    24 {
    25 accessorKey: 'city',
    26 header: 'City',
    27 },
    28 ],
    29 [],
    30 );
    31
    32 const table = useMaterialReactTable({
    33 columns,
    34 data,
    35 enableRowPinning: true,
    36 enablePagination: false,
    37 enableStickyHeader: true,
    38 rowPinningDisplayMode: 'top-and-bottom',
    39 getRowId: (row) => row.email,
    40 muiTableContainerProps: {
    41 sx: {
    42 maxHeight: '400px',
    43 },
    44 },
    45 });
    46
    47 return <MaterialReactTable table={table} />;
    48};
    49
    50export default Example;
    51

    Alternative Selection Row Pinning UI

    By default, the row pinning feature adds a pinning display column with pinning buttons for each row. However, you can instead combine the row pinning feature with the row selection feature to pin selected rows.

    const table = useMaterialReactTable({
    columns,
    data,
    enableRowPinning: true,
    enableRowSelection: true,
    rowPinningDisplayMode: 'select-sticky',
    });

    Demo

    DylanMurraydmurray@yopmail.comEast Daphne
    RaquelKohlerrkholer33@yopmail.comColumbus
    ErvinReingerereinger@mailinator.comSouth Linda
    BrittanyMcCulloughbmccullough44@mailinator.comLincoln
    BransonFramibframi@yopmain.comNew York
    BenMurraybenm@email.comSalt Lake City
    ElenaSmithesmith@yopmail.comLos Angeles
    MichaelJohnsonmjohnson@mailinator.comChicago
    SophiaBrownsbrown@yopmail.comHouston
    LucasDavisldavis@mailinator.comPhoenix
    OliviaGarciaogarcia@yopmail.comPhiladelphia
    LiamRodriguezlrodriguez@mailinator.comSan Antonio
    EmmaMartinezemartinez@yopmail.comSan Diego
    NoahHernandeznhernandez@mailinator.comDallas
    AvaLopezalopez@yopmail.comSan Jose
    WilliamGonzalezwgonzalez@mailinator.comAustin
    IsabellaWilsoniwilson@yopmail.comJacksonville
    JamesAndersonjanderson@mailinator.comFort Worth
    MiaThomasmthomas@yopmail.comColumbus
    AlexanderTaylorataylor@mailinator.comCharlotte
    GraceMooregmoore@yopmail.comIndianapolis
    EthanWhiteewhite@mailinator.comSan Francisco
    LilyHarrislharris@yopmail.comSeattle
    DanielMartindmartin@mailinator.comDenver
    ZoeJacksonzjackson@yopmail.comBoston
    MatthewThompsonmthompson@mailinator.comNashville
    EllaGarciaegarcia@yopmail.comDetroit
    DavidMartinezdmartinez@mailinator.comPortland
    AriaRobinsonarobinson@yopmail.comLas Vegas
    JosephClarkjclark@mailinator.comBaltimore

    Source Code

    1import { useMemo } from 'react';
    2import {
    3 MaterialReactTable,
    4 useMaterialReactTable,
    5 type MRT_ColumnDef,
    6} from 'material-react-table';
    7import { data, type Person } from './makeData';
    8
    9const Example = () => {
    10 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    11 //column definitions...
    32 );
    33
    34 const table = useMaterialReactTable({
    35 columns,
    36 data,
    37 enablePagination: false,
    38 enableRowPinning: true,
    39 enableRowSelection: true,
    40 enableStickyHeader: true,
    41 rowPinningDisplayMode: 'select-sticky',
    42 getRowId: (row) => row.email,
    43 initialState: {
    44 rowPinning: {
    45 top: ['ereinger@mailinator.com'],
    46 },
    47 rowSelection: {
    48 'ereinger@mailinator.com': true,
    49 },
    50 },
    51 muiTableContainerProps: {
    52 sx: {
    53 maxHeight: '400px',
    54 },
    55 },
    56 muiTableBodyRowProps: ({ row, table }) => {
    57 const { density } = table.getState();
    58 return {
    59 sx: {
    60 //Set a fixed height for pinned rows
    61 height: row.getIsPinned()
    62 ? `${
    63 //Default mrt row height estimates. Adjust as needed.
    64 density === 'compact' ? 37 : density === 'comfortable' ? 53 : 69
    65 }px`
    66 : undefined,
    67 },
    68 };
    69 },
    70 });
    71
    72 return <MaterialReactTable table={table} />;
    73};
    74
    75export default Example;
    76