Row Pinning

Pinned rows appear either above or below the normal rows of a table. This feature in other grids is also known as
“Frozen Rows” or “Floating Rows”.

To put pinned rows into your grid, set the Grid Options pinnedTopRowData or pinnedBottomRowData in the same way as
you would set normal data into rowData.

dashGridOptions = {
    'pinnedTopRowData': [],
    'pinnedBottomRowData': [],
}

pinnedTopRowData (any [ ]) Data to be displayed as pinned top rows in the grid.
pinnedBottomRowData (any [ ]) Data to be displayed as pinned bottom rows in the grid.

Note that Cell Editing and Cell Rendering can take place as normal on pinned rows.
If you want to use a different Cell Renderer for pinned rows and normal rows, use the Column Definition
parameter cellRendererSelector to specify different Cell Renderers for different rows.
See example Pinned Bottom Rows.

Pinned Top Rows

This example pins the selected row to the top row of the grid.

import dash_ag_grid as dag
from dash import Dash, html, Input, Output, Patch, callback
import plotly.express as px

app = Dash(__name__)

df = px.data.gapminder()

columnDefs = [
    {"field": "country", "checkboxSelection": True},
    {
        "field": "lifeExp",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format('.1f')(params.value)"},
    },
    {
        "field": "pop",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format(',.0f')(params.value)"},
    },
    {
        "field": "gdpPercap",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
    },
]

app.layout = html.Div(
    [
        dag.AgGrid(
            id="row-pinning-top",
            rowData=df.to_dict("records"),
            columnDefs=columnDefs,
            defaultColDef={"editable": True, "filter": True},
            columnSize="sizeToFit",
            dashGridOptions={"rowSelection": "multiple", "animateRows": False},
        ),
    ],
)


@callback(
    Output("row-pinning-top", "dashGridOptions"),
    Input("row-pinning-top", "selectedRows"),
)
def row_pinning_top(selected_rows):
    grid_option_patch = Patch()
    grid_option_patch["pinnedTopRowData"] = selected_rows
    return grid_option_patch


if __name__ == "__main__":
    app.run(debug=True)

Pinned Bottom Rows

This example pins a summary row to the bottom of the grid.

The following can be noted:

View the JavaScript functions used for this example

These JavaScript functions must be added to the dashAgGridFunctions.js file in the assets folder.
See JavaScript Functions
for more information.

var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};

dagfuncs.rowPinningBottom = function (params) {

    if (params.node.rowPinned) {
        // Text of pinned row is bold for all columns
        let style = {fontWeight: "bold"};

        if (params.colDef.field === "country") {
            // Add text size = 25 for "Average"
            style["fontSize"] = 25
        } else if (["lifeExp", "pop", "gdpPercap"].includes(params.colDef.field)) {
            // Add blue text color for means
            style["color"] = "#2186f4"
        }

        return {
            component: window.dashAgGridComponentFunctions.RowPinningBottomComponent,
            params: {style: style},
        };
    } else {
        // rows that are not pinned don't use any cell renderer
        return undefined;
    }
}

View Custom Cell Renderer used for this example

This JavaScript function must be added to the dashAgGridComponentFunctions.js file in the assets folder.
See Custom Components for more
information.

var dagcomponentfuncs = (window.dashAgGridComponentFunctions = window.dashAgGridComponentFunctions || {});

dagcomponentfuncs.RowPinningBottomComponent = function (props) {
    return React.createElement('span', {style: props.style}, props.value)
}
import dash_ag_grid as dag
from dash import Dash, html, Input, Output, Patch, callback
import plotly.express as px
import pandas as pd

app = Dash(__name__)

df = px.data.gapminder()

columnDefs = [
    {"field": "country", "filter": True, "floatingFilter": True},
    {"field": "year", "filter": "agNumberColumnFilter", "floatingFilter": True},
    {
        "field": "lifeExp",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format('.1f')(params.value)"},
    },
    {
        "field": "pop",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format(',.0f')(params.value)"},
    },
    {
        "field": "gdpPercap",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
    },
]

app.layout = html.Div(
    [
        dag.AgGrid(
            id="row-pinning-bottom",
            rowData=df.to_dict("records"),
            columnDefs=columnDefs,
            defaultColDef={"editable": True, 'cellRendererSelector': {"function": "rowPinningBottom(params)"}},
            columnSize="sizeToFit",
            dashGridOptions={"animateRows": False},
        ),
    ],
)


@callback(
    Output("row-pinning-bottom", "dashGridOptions"),
    Input("row-pinning-bottom", "virtualRowData"),
)
def row_pinning_bottom(data):
    dff = df if data is None else pd.DataFrame(data)
    means = dff[["lifeExp", "pop", "gdpPercap"]].mean() if data else {"lifeExp": 0, "pop": 0, "gdpPercap": 0}

    # Using custom cell renderer doesn't apply "valueFormatter", so we can format the values here
    means_formatted = {
        "lifeExp": f"{means['lifeExp']:.1f}",
        "pop": f"{means['pop']:,.0f}",
        "gdpPercap": f"${means['gdpPercap']:,.2f}"
    }

    grid_option_patch = Patch()
    grid_option_patch["pinnedBottomRowData"] = [{"country": "Average", **means_formatted}]
    return grid_option_patch


if __name__ == "__main__":
    app.run(debug=True)

Non Supported Items

Pinned rows are not part of the main row model. For this reason, the following is not possible: