Styling Cells

Cell customization is done at the column level via columnDefs or defaultColDef, using the properties:

Some cell styles may also be overridden with CSS variables. See the
full CSS variables reference.

Cell Styles

To apply CSS Styles to the cells in a column, it is possible to use the Column Property:

cellStyle (dict | function) The style properties to apply to the cells. Set to a dictionary or a function returning a
dictionary, where the keys are the style name and the values are the style value.

With the Dash AG Grid Component, it is also possible to use cellStyle using the special keys styleConditions
and/or defaultStyle to provide a set of rules (similar to cellClassRules):

cellStyle (dict) The styles to apply for each cell individually. Dict with the keys:

Same Styles for All Cells

By providing a dictionary with the CSS styles, it will be applied to all the cells in the column. For example:

columnDefs = [
    {
        'field': 'sickDays',
        'cellStyle': {'background-color': '#66c2a5'}
    },
]

Conditional Cells Styles

To apply CSS styles to cells based on conditions or values, it is possible to provide to cellStyle, either a function:

columnDefs = [
    {
        'field': 'sickDays',
        'cellStyle': {
            "function": "params.value && {'backgroundColor': 'rgb(255,0,0,' + params.value/8 + ')'}"
        }
    },
]

Or a set of rules:

columnDefs = [
    {
        'field': 'sickDays',
        'cellStyle': {
            # Set of rules
            "styleConditions": [
                {
                    "condition": "[5,6,7].includes(params.value)",
                    "style": {"backgroundColor": "sandybrown"},
                },
                {
                    "condition": "params.value >= 8",
                    "style": {"backgroundColor": "lightcoral"},
                },
            ],
            # Default style if no rules apply
            "defaultStyle": {"backgroundColor": "mediumaquamarine"},
        }
    },
]

The following example shows the result using cellStyle with different options.

Note that:

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

app = Dash(__name__)

rowData = [
    {"employee": "Josh Finch", "sickDays": 4},
    {"employee": "Flavia Mccloskey", "sickDays": 1},
    {"employee": "Marine Creason", "sickDays": 8},
    {"employee": "Carey Livingstone", "sickDays": 2},
    {"employee": "Brande Giorgi", "sickDays": 5},
    {"employee": "Beatrice Kugler", "sickDays": 3},
    {"employee": "Elvia Macko", "sickDays": 7},
    {"employee": "Santiago Little", "sickDays": 1},
]

cell_styles = {
    'all': {'background-color': 'mediumaquamarine'},
    'function': {
        "function": "params.value && {'backgroundColor': 'rgb(255,0,0,' + params.value/8 + ')'}"
    },
    'rules': {
        "styleConditions": [
            {
                "condition": "[5,6,7].includes(params.value)",
                "style": {"backgroundColor": "lightsalmon"},
            },
            {
                "condition": "params.value >= 8",
                "style": {"backgroundColor": "lightcoral"},
            },
        ],
        "defaultStyle": {"backgroundColor": "mediumaquamarine"},
    },
}

columnDefs = [
    {"field": "employee"},
    {"field": "sickDays", "editable": True},
]

app.layout = html.Div(
    [
        dcc.RadioItems(
            id="radio-styling-cells-styles",
            options={
                "all": 'All Cells Styling',
                "function": 'Conditional Cells Styling - Using a function',
                "rules": 'Conditional Cells Styling - Using rules',
            },
            value="all",
        ),
        html.Pre(id='pre-styling-cells-styles'),
        dag.AgGrid(
            id="styling-cells-styles",
            rowData=rowData,
            columnDefs=columnDefs,
            columnSize="responsiveSizeToFit",
            dashGridOptions={"animateRows": False}
        ),
    ],
)


@callback(
    Output("styling-cells-styles", "columnDefs"),
    Output("pre-styling-cells-styles", "children"),
    Input("radio-styling-cells-styles", "value"),
)
def styling_cells_styles(value):
    return (
        [
            {"field": "employee"},
            {"field": "sickDays", "editable": True, "cellStyle": cell_styles[value]},
        ],
        f'\n"cellStyle": {cell_styles[value]}\n' if value != 'rules' else
        '''
"cellStyle": {
    "styleConditions": [
        {
            "condition": "[5,6,7].includes(params.value)",
            "style": {"backgroundColor": "sandybrown"},
        },
        {
            "condition": "params.value >= 8",
            "style": {"backgroundColor": "lightcoral"},
        },
    ],
    "defaultStyle": {"backgroundColor": "mediumaquamarine"},
}
'''
    )


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

  

Cell Classes

To apply CSS Classes to the cells in a column, it is possible to use the Column Properties:

cellClass (string | function) The classes to apply to the cells. Set to a string or a function returning
a string, containing the classes to apply spaces separated.

cellClassRules (dict) Rules which can be applied to include certain CSS classes. The keys are the class names and
the values are expressions that if evaluated to true, the classes get used.

Same Classes for All Cells

By providing a string with the CSS Classes, it will be applied to all the cells in the column. For example:

columnDefs = [
    {
        "field": "employee",
        "cellClass": "bg-secondary bg-gradient bg-opacity-50",
    },
]

Conditional Cells Classes

To apply CSS Classes to cells based on conditions or values, it is possible to provide a function to cellClass:

columnDefs = [
    {
        "field": "borderColor",
        'cellClass': {"function": "'border border-3 border-' + params.value"},
    },
]

Or a set of rules to cellClassRules:

columnDefs = [
    {
        "field": "sickDays",
        'cellClassRules': {
            'text-danger text-end fs-3': '8 <= params.value',
            'text-warning text-center fs-4': '5 <= params.value &&  params.value < 8  ',
            'text-success text-start fs-6': 'params.value < 5',
        },
    },
]

The following example shows the result using cellClass and cellClassRules. It uses imported Bootstrap classes.

Note that:

import dash_ag_grid as dag
from dash import Dash, html
import dash_bootstrap_components as dbc

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

rowData = [
    {"employee": "Josh Finch", "sickDays": 4, "borderColor": "primary"},
    {"employee": "Flavia Mccloskey", "sickDays": 1, "borderColor": "success"},
    {"employee": "Marine Creason", "sickDays": 8, "borderColor": "light"},
    {"employee": "Carey Livingstone", "sickDays": 2, "borderColor": "light"},
    {"employee": "Brande Giorgi", "sickDays": 5, "borderColor": "light"},
    {"employee": "Beatrice Kugler", "sickDays": 3, "borderColor": "light"},
    {"employee": "Elvia Macko", "sickDays": 7, "borderColor": "light"},
    {"employee": "Santiago Little", "sickDays": 1, "borderColor": "light"},
]

columnDefs = [
    {
        "field": "employee",
        "cellClass": "bg-secondary bg-gradient bg-opacity-50",
    },
    {
        "field": "sickDays",
        'cellClassRules': {
            'text-danger text-end fs-3': '8 <= params.value',
            'text-warning text-center fs-4': '5 <= params.value &&  params.value < 8  ',
            'text-success text-start fs-6': 'params.value < 5',
        },
    },
    {
        "field": "borderColor",
        'cellClass': {"function": "'border border-3 border-' + params.value"},
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "values": ["primary", "secondary", "success", "info", "warning", "danger", "light", "dark"],
        },
    },
]

app.layout = html.Div(
    [
        dag.AgGrid(
            id="styling-cells-classes",
            rowData=rowData,
            columnDefs=columnDefs,
            defaultColDef={"editable": True},
            columnSize="responsiveSizeToFit",
            dashGridOptions={"animateRows": False}
        ),
    ],
)

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

Conditional Formatting 'params'

Note that, when using conditional formatting to apply styles or classes, the properties available through params that
can be used for the conditions are:

Refresh of Styles

If you refresh a cell, or a cell is updated due to editing, the cellStyle, cellClass and cellClassRules are
applied again. This has the following effect:

If you are using cellStyle to highlight changing data, then please take note that the grid will not remove styles. For
example if you are setting text color to 'red' for a condition, then you should explicitly set it back to default, for
example 'black' when the condition is not met. Otherwise, the highlight will remain once it’s first applied.

# unsafe, the red will stay after initially applied
columnDefs = [
    {
        'field': 'col1',
        'cellStyle': {
            "function": "params.value > 5 ? {'color': 'red'} : null"
        }
    },
]

# safe, the black will override the red when the condition is not true
columnDefs = [
    {
        'field': 'col1',
        'cellStyle': {
            "function": "params.value > 5 ? {'color': 'red'} : {'color': 'black'}"
        }
    },
]

Refresh Conditional Formatting Depending on Other Columns

As explained in Refresh of Styles,
the cellStyle, cellClass and cellClassRules are re-applied if a cell is refreshed or edited.

This means if a column uses a conditional formatting depending on other columns and those columns are edited, the former
column’s formatting will not be automatically updated. It has to be refreshed or edited.

To force the column employee to refresh, it is possible to use the function of the grid
API gridApi.refreshCells({force: true, columns: ['employee']}). Note that the grid API is available through a
clientside callback.

The following example shows the difference between the default behavior and the behavior when we force the grid to
refresh the Employee column when the Sick Days is edited.

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

app = Dash(__name__)

rowData = [
    {"employee": "Josh Finch", "sickDays": 4},
    {"employee": "Flavia Mccloskey", "sickDays": 1},
    {"employee": "Marine Creason", "sickDays": 8},
    {"employee": "Carey Livingstone", "sickDays": 2},
    {"employee": "Brande Giorgi", "sickDays": 5},
    {"employee": "Beatrice Kugler", "sickDays": 3},
    {"employee": "Elvia Macko", "sickDays": 7},
    {"employee": "Santiago Little", "sickDays": 1},
]

columnDefs = [
    {
        "field": "employee",
        "cellStyle": {
            "styleConditions": [
                {
                    "condition": "[5,6,7].includes(params.data.sickDays)",
                    "style": {"backgroundColor": "lightsalmon"},
                },
                {
                    "condition": "params.data.sickDays >= 8",
                    "style": {"backgroundColor": "lightcoral"},
                },
            ],
            "defaultStyle": {"backgroundColor": "mediumaquamarine"},
        }},
    {"field": "sickDays", "editable": True},
]

app.layout = html.Div(
    [
        dcc.Checklist(
            id="chk-styling-cells-other-col",
            options={"force_refresh_ON": 'Force Refresh of the Column Employee'},
            value=[]
        ),
        dag.AgGrid(
            id="styling-cells-other-col",
            rowData=rowData,
            columnDefs=columnDefs,
            columnSize="responsiveSizeToFit",
            dashGridOptions={"animateRows": False}
        ),
    ],
)

clientside_callback(
    """async function (changedCell, forceRefresh) {
        gridApi = await dash_ag_grid.getApiAsync('styling-cells-other-col')
        forceRefresh.length != 0 && gridApi.refreshCells({force: true, columns: ['employee']})
        return window.dash_clientside.no_update    
    }""",
    Output('styling-cells-other-col', 'cellValueChanged'),
    Input('styling-cells-other-col', 'cellValueChanged'),
    State('chk-styling-cells-other-col', 'value'),
    prevent_intial_Call=True
)

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

Cell Shading Examples

The next two examples are based
on DataTable examples.
These recipes shade cells with cellStyle and styleConditions and creates a legend with HTML components. You’ll need
to pip install colorlover to get the colorscales.

from dash import Dash, html
from dash_ag_grid import AgGrid
import pandas as pd
import colorlover


wide_data = [
    {"Firm": "Acme", "2017": 13, "2018": 5, "2019": 10, "2020": 4},
    {"Firm": "Olive", "2017": 3, "2018": 3, "2019": 13, "2020": 3},
    {"Firm": "Barnwood", "2017": 6, "2018": 7, "2019": 3, "2020": 6},
    {"Firm": "Henrietta", "2017": -3, "2018": -10, "2019": -5, "2020": -6},
]
df = pd.DataFrame(wide_data)

app = Dash(__name__)


def discrete_background_color_bins(df, n_bins=5, columns="all"):
    bounds = [i * (1.0 / n_bins) for i in range(n_bins + 1)]
    if columns == "all":
        df_numeric_columns = df.select_dtypes("number")
    else:
        df_numeric_columns = df[columns]
    df_max = df_numeric_columns.max().max()
    df_min = df_numeric_columns.min().min()
    ranges = [((df_max - df_min) * i) + df_min for i in bounds]
    styleConditions = []
    legend = []
    for i in range(1, len(bounds)):
        min_bound = ranges[i - 1]
        max_bound = ranges[i]
        if i == len(bounds) - 1:
            max_bound += 1

        backgroundColor = colorlover.scales[str(n_bins)]["seq"]["Blues"][i - 1]
        color = "white" if i > len(bounds) / 2.0 else "inherit"

        styleConditions.append(
            {
                "condition": f"params.value >= {min_bound} && params.value < {max_bound}",
                "style": {"backgroundColor": backgroundColor, "color": color},
            }
        )

        legend.append(
            html.Div(
                [
                    html.Div(
                        style={
                            "backgroundColor": backgroundColor,
                            "borderLeft": "1px rgb(50, 50, 50) solid",
                            "height": "10px",
                        }
                    ),
                    html.Small(round(min_bound, 2), style={"paddingLeft": "2px"}),
                ],
                style={"display": "inline-block", "width": "60px"},
            )
        )

    return styleConditions, html.Div(legend, style={"padding": "5px 0 5px 0"})


styleConditions, legend = discrete_background_color_bins(df)

app.layout = html.Div(
    [
        html.H5("Highlighting Cells by Value with a Colorscale Like a Heatmap"),
        legend,
        AgGrid(
            id="styling-cells-shading-1",
            rowData=df.to_dict("records"),
            columnDefs=[{"field": i} for i in df.columns],
            defaultColDef={"cellStyle": {"styleConditions": styleConditions}},
            columnSize="responsiveSizeToFit",
            dashGridOptions={"animateRows": False}
        ),
    ]
)

if __name__ == "__main__":
    app.run(debug=True)
Highlighting Cells by Value with a Colorscale Like a Heatmap
-10.0
-5.4
-0.8
3.8
8.4
from dash import Dash, html
from dash_ag_grid import AgGrid
import pandas as pd
import colorlover


wide_data = [
    {"Firm": "Acme", "2017": 13, "2018": 5, "2019": 10, "2020": 4},
    {"Firm": "Olive", "2017": 3, "2018": 3, "2019": 13, "2020": 3},
    {"Firm": "Barnwood", "2017": 6, "2018": 7, "2019": 3, "2020": 6},
    {"Firm": "Henrietta", "2017": -3, "2018": -10, "2019": -5, "2020": -6},
]
df = pd.DataFrame(wide_data)

app = Dash(__name__)


def discrete_background_color_bins(df, n_bins=5, columns="all"):
    bounds = [i * (1.0 / n_bins) for i in range(n_bins + 1)]
    if columns == "all":
        df_numeric_columns = df.select_dtypes("number")
    else:
        df_numeric_columns = df[columns]
    df_max = df_numeric_columns.max().max()
    df_min = df_numeric_columns.min().min()
    ranges = [((df_max - df_min) * i) + df_min for i in bounds]
    styleConditions = []
    legend = []
    for i in range(1, len(bounds)):
        min_bound = ranges[i - 1]
        max_bound = ranges[i]
        if i == len(bounds) - 1:
            max_bound += 1

        backgroundColor = colorlover.scales[str(n_bins)]["seq"]["Blues"][i - 1]
        color = "white" if i > len(bounds) / 2.0 else "inherit"

        styleConditions.append(
            {
                "condition": f"params.value >= {min_bound} && params.value < {max_bound}",
                "style": {"backgroundColor": backgroundColor, "color": color},
            }
        )

        legend.append(
            html.Div(
                [
                    html.Div(
                        style={
                            "backgroundColor": backgroundColor,
                            "borderLeft": "1px rgb(50, 50, 50) solid",
                            "height": "10px",
                        }
                    ),
                    html.Small(round(min_bound, 2), style={"paddingLeft": "2px"}),
                ],
                style={"display": "inline-block", "width": "60px"},
            )
        )

    return styleConditions, html.Div(legend, style={"padding": "5px 0 5px 0"})


styleConditions, legend = discrete_background_color_bins(df, columns=["2018"])

columnDefs = [
    {"field": "Firm"},
    {"field": "2017"},
    {"field": "2018", "cellStyle": {"styleConditions": styleConditions}},
    {"field": "2019"},
    {"field": "2020"},
]


app.layout = html.Div(
    [
        html.H5("Highlighting with a Colorscale on a Single Column"),
        legend,
        AgGrid(
            id="styling-cells-shading-2",
            rowData=df.to_dict("records"),
            columnDefs=columnDefs,
            columnSize="responsiveSizeToFit",
            dashGridOptions={"animateRows": False}
        ),
    ]
)

if __name__ == "__main__":
    app.run(debug=True)
Highlighting with a Colorscale on a Single Column
-10.0
-6.6
-3.2
0.2
3.6

This third example also shows cells styling to create a heatmap providing a function to the cellStyle parameter.

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.heatMap = function (props) {
    const {min, max} = props.colDef.cellRendererParams;
    const val = props.value;

    if (val > 0) {
        g = 255;
        r = b = 255 * (1 - val / max);
    } else {
        r = 255;
        g = b = 255 * (1 - val / min);
    }

    return {
        backgroundColor: 'rgb(' + [r, g, b].join() + ')',
        color: 'black',
    }
};
import dash_ag_grid as dag
from dash import Dash, html
import pandas as pd
import numpy as np


df = pd.DataFrame(np.random.randint(-100, 100, size=(10, 6)), columns=list("abcdef"))
df["items"] = [f"Item {i}" for i in range(len(df))]
df_numeric_columns = df.select_dtypes("number")
min = df_numeric_columns.min().min()
max = df_numeric_columns.max().max()

columnDefs = [{"field": "items"}] + [
    {
        "field": field,
        "cellStyle": {"function": "heatMap(params)"},
        "cellRendererParams": {"min": min, "max": max},
    }
    for field in df.columns[:-1]
]

app = Dash(__name__)

app.layout = html.Div(
    [
        dag.AgGrid(
            id="styling-cells-shading-3",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            columnSize="responsiveSizeToFit",
            dashGridOptions={"suppressRowHoverHighlight": True, "animateRows": False},
        )
    ]
)

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