Scroll To

Use the scrollTo prop to scroll to a specific position in the grid.

Requires dash-ag-grid>=2.2.0

scrollTo is a dict with keys:

NOTE: If any of rowIndex, rowId, and data are passed to scrollTo simultaneously only one of them will be used as all of them set the vertical scroll position.
The order of priority will be rowIndex, then rowId, and finally data.

Scroll To Row Index

This example scrolls to the row index, typically the row number. You can also specify if the specified index should be at the top, middle or bottom of the viewport, and scroll horizontally to ensure that a column is visible.

import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, State, callback
import pandas as pd
import dash_bootstrap_components as dbc

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)

columnDefs = [
    {"headerName": "Row", "valueGetter": {"function": "params.node.rowIndex", 'pinned': True}}
] + [{"field": c} for c in df.columns]

app.layout = dbc.Container(
    [
        dbc.Row(
            [
                dbc.Col(
                    [
                        dbc.Label("Row index"),
                        dbc.Input(
                            id="row-index-scroll-to",
                            type="number",
                            min=0,
                            max=df.shape[0] - 1,
                            step=1,
                        ),
                        dbc.Label("Row Position"),
                        dcc.Dropdown(
                            options=["top", "bottom", "middle"],
                            id="row-position-scroll-to",
                        ),
                    ]
                ),
                dbc.Col(
                    [
                        dbc.Label("Column"),
                        dcc.Dropdown(options=df.columns, id="column-scroll-to"),
                        dbc.Label("Column Position"),
                        dcc.Dropdown(
                            options=["auto", "start", "middle", "end"],
                            id="column-position-scroll-to",
                        ),
                    ]
                ),
            ],
            className="mb-2",
        ),
        dag.AgGrid(
            id="grid-scroll-to",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            columnSize="sizeToFit",
            defaultColDef={"resizable": True, "sortable": True, "minWidth": 150},
        ),
        html.Div(id="out-scroll-to"),
    ],
    fluid=True,
)


@callback(
    Output("out-scroll-to", "children"),
    Input("grid-scroll-to", "scrollTo"),
)
def show_scroll(scroll):
    return  f"scroll_to = {str(scroll)}"


@callback(
    Output("grid-scroll-to", "scrollTo"),
    Input("row-index-scroll-to", "value"),
    Input("column-scroll-to", "value"),
    Input("row-position-scroll-to", "value"),
    Input("column-position-scroll-to", "value"),
    State("grid-scroll-to", "scrollTo"),
)
def scroll_to_row_and_col(row_index, column, row_position, column_position, scroll_to):
    if not scroll_to:
        scroll_to = {}
    scroll_to["rowIndex"] = row_index
    scroll_to["column"] = column
    scroll_to["rowPosition"] = row_position
    scroll_to["columnPosition"] = column_position
    return scroll_to


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

Scroll To Row Id

This example will scroll vertically to a unique row id, rather than scrolling to a row number like the example above. Try sorting a column in each example to see the difference.

In this example we create a unique id using the index of the dataframe. See more
information the Row IDs section.

import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, State, callback
import pandas as pd
import dash_bootstrap_components as dbc

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)
df["id"] = df.index


columnDefs = [
    {
        "headerName": "Row #",
        "valueGetter": {"function": "params.node.rowIndex"},
        "width": 100,
    "pinned": True
    },
    {"field": "id", "width": 75, "pinned": True},
] + [{"field": c} for c in df.columns if c != "id"]

app.layout = dbc.Container(
    [
        dbc.Row(
            [
                dbc.Col(
                    [
                        dbc.Label("Row id"),
                        dbc.Input(
                            id="row-scroll-to-id",
                            type="number",
                            min=0,
                            max=df.shape[0] - 1,
                            step=1,
                        ),
                        dbc.Label("Position"),
                        dcc.Dropdown(
                            options=["top", "bottom", "middle"],
                            id="row-position-scroll-to-id",
                        ),
                    ]
                ),
                dbc.Col(
                    [
                        dbc.Label("Column"),
                        dcc.Dropdown(options=df.columns, id="column-scroll-to-id"),
                        dbc.Label("Position"),
                        dcc.Dropdown(
                            options=["auto", "start", "middle", "end"],
                            id="column-position-scroll-to-id",
                        ),
                    ]
                ),
            ],
            className="mb-2",
        ),
        dag.AgGrid(
            id="grid-scroll-to-id",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            defaultColDef={"resizable": True, "sortable": True},
            getRowId="params.data.id",
        ),
        html.Div(id="out-scroll-to-id"),
    ],
    fluid=True,
)


@callback(
    Output("out-scroll-to-id", "children"),
    Input("grid-scroll-to-id", "scrollTo"),
)
def show_scroll(scroll):
    return f"scroll_to = {str(scroll)}"


@callback(
    Output("grid-scroll-to-id", "scrollTo"),
    Input("row-scroll-to-id", "value"),
    Input("column-scroll-to-id", "value"),
    Input("row-position-scroll-to-id", "value"),
    Input("column-position-scroll-to-id", "value"),
    State("grid-scroll-to-id", "scrollTo"),
)
def scroll_to_row_and_col(row_id, column, row_position, column_position, scroll_to):
    if not scroll_to:
        scroll_to = {}
    scroll_to["rowId"] = str(row_id)
    scroll_to["column"] = column
    scroll_to["rowPosition"] = row_position
    scroll_to["columnPosition"] = column_position
    return scroll_to


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

Scroll To Row Data

Here we use the "data" key in the scrollTo prop to position the grid at a certain row.
Note the following:
- The data must be a single row in the same format as rowData
- Since we are not specifying position of the row and columns in the viewport, the grid uses the defaults:
{"rowPosition":"top", "columnPosition": "auto"}

import dash_ag_grid as dag
from dash import Dash, dcc, html, Input, Output, callback, no_update
import pandas as pd


app = Dash(__name__)

df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)
df = df.sort_values(by=["year", "country"])
rowData = df.to_dict("records")

app.layout = html.Div(
    [
        html.Label("Scroll to start of year:"),
        dcc.Dropdown(df.year.unique(), id="dd-scroll-to-data", style={"width": 200}),
        dag.AgGrid(
            id="grid-scroll-to-data",
            columnDefs=[{"field": c} for c in df.columns],
            rowData=rowData,
            defaultColDef={"resizable": True},
        ),
        html.Div(id="out-scroll-to-data"),
    ]
)


@callback(
    Output("out-scroll-to-data", "children"),
    Input("grid-scroll-to-data", "scrollTo"),
)
def show_scroll(scroll):
    return f"scroll_to = {str(scroll)}"

@callback(
    Output("grid-scroll-to-data", "scrollTo"),
    Input("dd-scroll-to-data", "value"),
    prevent_initial_call=True,
)
def scroll_to_data(value):
    if value is None:
        return no_update
    for row in rowData:
        if row["year"] == value:
            break
    return {"data": row}


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

Initial Scroll To Position

It’s possible to specify the initial Scroll To position when the app starts. This example sets the scrollTo prop in
the grid definition, here to start at row number 100, rather than only in a callback:

grid = dag.AgGrid(
    scrollTo={"rowIndex": 100},
    # other props
)
import dash_ag_grid as dag
from dash import Dash, html
import pandas as pd


app = Dash(__name__)

df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)


columnDefs = [
    {"headerName": "Row", "valueGetter": {"function": "params.node.rowIndex"}}
] + [{"field": c} for c in df.columns]

app.layout = html.Div(
    [
        dag.AgGrid(
            id="grid-scroll-to-start",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            defaultColDef={"resizable": True, "sortable": True},
            scrollTo={"rowIndex": 100},
        ),
    ]
)


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

Scroll To with Pagination

In order to scroll to a position, the row must exist the DOM. When using pagination, only rows on the current
page exist. To scroll to a row on a different page, the grid must be on that page prior to setting the scrollTo prop.

In this example we use a clientside callback to calculate which page the row is located and the paginationGoToPage
function to show the page. Note that it goes to the correct page based on the current state of the grid, including sort and/or filters applied.

import dash_ag_grid as dag
from dash import Dash, dcc, html, Input, Output, clientside_callback
import pandas as pd


app = Dash(__name__)

df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)
df["id"] = df.index


columnDefs = [
    {
        "headerName": "Row #",
        "valueGetter": {"function": "params.node.rowIndex"},
        "width": 100,
    },
    {"field": "id", "width": 75},
] + [{"field": c} for c in df.columns if c != "id"]


app.layout = html.Div(
    [
        html.Label("Scroll to row id:"),
        dcc.Input(id="input-scroll-to-pagination", min=0, max=df.shape[0], type="number"),
        dag.AgGrid(
            id="grid-scroll-to-pagination",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            defaultColDef={"resizable": True, "sortable": True},
            getRowId="params.data.id",
            dashGridOptions={"pagination": True, "paginationPageSize": 50},
        ),
    ]
)

clientside_callback(
    """function (rowId) {
        if (rowId) {
            grid = dash_ag_grid.getApi("grid-scroll-to-pagination")        
            rowIndex = grid.getRowNode(rowId).rowIndex        
            pageTarget = Math.floor(rowIndex / grid.paginationGetPageSize())
            grid.paginationGoToPage(pageTarget)
        }
        return {"rowId": rowId.toString()}
    }""",
    Output("grid-scroll-to-pagination", "scrollTo"),
    Input("input-scroll-to-pagination", "value"),
    prevent_initial_call=True,
)


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

Scroll To with Infinite Row Model

The scrollTo prop works with both the clientside and serverside row models. Here is an example with the Infinite Row Model.

import dash_ag_grid as dag
from dash import Dash, Input, Output, dcc, html, no_update, callback
import pandas as pd


app = Dash(__name__)


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)


columnDefs = [
    # this column shows the row index, doesn't use any data from the row
    {
        "headerName": "ID",
        "maxWidth": 100,
        # it is important to have node.id here, so that when the id changes (which happens
        # when the row is loaded) then the cell is refreshed.
        "valueGetter": {"function": "params.node.id"},
    },
    {"field": "athlete", "minWidth": 150},
    {"field": "country", "minWidth": 150},
    {"field": "year"},
    {"field": "sport", "minWidth": 150},
    {"field": "total"},
]

defaultColDef = {
    "flex": 1,
    "sortable": False,
    "resizable": True,
}


app.layout = html.Div(
    [
        dcc.Markdown("Infinite scroll:  No sorting or filtering"),
        html.Label("Scroll to row id:"),
        dcc.Input(id="input-scroll-to-infinite", min=0, max=df.shape[0], type="number"),
        dag.AgGrid(
            id="grid-scroll-to-infinite",
            columnDefs=columnDefs,
            defaultColDef=defaultColDef,
            rowModelType="infinite",
            dashGridOptions={
                # The number of rows rendered outside the viewable area the grid renders.
                "rowBuffer": 0,
                # How many blocks to keep in the store. Default is no limit, so every requested block is kept.
                "maxBlocksInCache": 10,
                "cacheBlockSize": 100,
                "cacheOverflowSize": 2,
                "maxConcurrentDatasourceRequests": 1,
                "infiniteInitialRowCount": 1000,
            },
        ),
    ],
)




@callback(
    Output("grid-scroll-to-infinite", "scrollTo"),
    Input("input-scroll-to-infinite", "value"),
)
def scroll_to_infinite(value):
    return {"rowIndex": value}


@callback(
    Output("grid-scroll-to-infinite", "getRowsResponse"),
    Input("grid-scroll-to-infinite", "getRowsRequest"),
)
def infinite_scroll(request):
    if request is None:
        return no_update
    partial = df.iloc[request["startRow"] : request["endRow"]]
    return {"rowData": partial.to_dict("records"), "rowCount": len(df.index)}


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

Infinite scroll: No sorting or filtering

Scroll To with Row Groups

As with pagination, when using Row Groups (an AG Grid Enterprise feature), the row group must be expanded prior to setting the scrollTo prop.
See an example in the Scroll To With Row Groups example in the Enterprise section.