Styling dash-ag-grid ≥ v33 with Bootstrap or Mantine (Light and Dark Mode)

AG Grid v33+ and (dash-ag-grid v33+) introduced a new theming API which makes it much easier to style the grid.

You can find more information and lots of great examples in the dash-ag-grid documentation. Also, see the migration guide if you are updating from a previous version.

In earlier versions of dash-ag-grid, the theme was set using the className prop. The easiest way to switch between light and dark mode was to update the grid’s className in a callback, which caused the grid to re-render and often had a visible lag.

The examples below use Mantine or Bootstrap CSS variables in the grid’s new theme prop. When the app theme changes, the grid’s theme is automatically updated. No callback required to update grid properties when the theme changes :tada:

Example 1: dash-bootstrap-components

This example uses Bootstrap CSS variables for background, text, and accent colors in the grid’s theme prop. When the app theme switches between light and dark mode, the grid theme automatically updates.

dbc-ag-grid-theme2

# dash-bootstrap-components>=1.5.0
# dash-ag-grid>=33.3.3
from dash import Dash, html, Input, Output, clientside_callback
import dash_bootstrap_components as dbc
import dash_ag_grid as dag
import pandas as pd

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

app = Dash(__name__, external_stylesheets=[dbc.themes.MINTY, dbc.icons.FONT_AWESOME])

color_mode_switch = html.Span(
    [
        dbc.Label(className="fa fa-moon", html_for="color-mode-switch"),
        dbc.Switch(
            id="color-mode-switch",
            value=False,
            className="d-inline-block ms-1",
            persistence=True,
        ),
        dbc.Label(className="fa fa-sun", html_for="color-mode-switch"),
    ]
)

columnDefs = [
    {"field": "athlete", "filter": True},
    {"field": "country"},
    {"field": "sport"},
    {"field": "year"},
]

grid = dag.AgGrid(
    id="theme-color-scheme",
    rowData=df.to_dict("records"),
    columnDefs=columnDefs,
    defaultColDef={"flex": 1},
    dashGridOptions={
        "theme": {
            "function": (
                "themeQuartz.withParams({"
                "backgroundColor: 'var(--bs-body-bg)', "
                "foregroundColor: 'var(--bs-body-color)', "
                "accentColor: 'var(--bs-primary)', "
                "fontFamily: 'var(--bs-font-family)', "
                "headerFontWeight: 'bold'"
                "})"
            ),
        },
        "rowSelection": {"mode": "multiRow"},
    },
)

app.layout = dbc.Container(
    [
        html.H3("Bootstrap Light and Dark Mode Demo", className="bg-primary p-2"),
        color_mode_switch,
        grid,
    ]
)

clientside_callback(
    """
    (switchOn) => {
        document.documentElement.setAttribute(
            'data-bs-theme',
            switchOn ? 'light' : 'dark'
        );
        return window.dash_clientside.no_update;
    }
    """,
    Output("color-mode-switch", "id"),
    Input("color-mode-switch", "value"),
)

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

Example 2: dash-mantine-components

The same approach works with Mantine. The grid theme uses Mantine’s CSS variables, so switching the Mantine color scheme automatically updates the grid.

Just a heads up… The next Dash Mantine Components release (v2.6.0) will include a new ColorSchemeToggle component which switches the theme without having to write your own dash callback to set the mantine theme attribute.

# dash-mantine-components == 2.5.0
# dash-ag-grid >= 33.3.3
import dash_mantine_components as dmc
from dash_iconify import DashIconify
from dash import Dash, Input, Output, clientside_callback
import dash_ag_grid as dag
import pandas as pd

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

app = Dash()

theme_toggle = dmc.ActionIcon(
    [
        dmc.Paper(DashIconify(icon="radix-icons:sun", width=25), darkHidden=True),
        dmc.Paper(DashIconify(icon="radix-icons:moon", width=25), lightHidden=True),
    ],
    variant="transparent",
    color="yellow",
    id="color-scheme-toggle",
    size="lg",
)

columnDefs = [
    {"field": "athlete", "filter": True},
    {"field": "country"},
    {"field": "sport"},
    {"field": "year"},
]

grid = dag.AgGrid(
    id="theme-color-scheme2",
    rowData=df.to_dict("records"),
    columnDefs=columnDefs,
    defaultColDef={"flex": 1},
    dashGridOptions={
        "theme": {
            "function": (
                "themeQuartz.withParams({"
                "backgroundColor: 'var(--mantine-color-body)', "
                "foregroundColor: 'var(--mantine-color-text)', "
                "accentColor: 'var(--mantine-primary-color-filled)', "
                "fontFamily: 'var(--mantine-font-family)', "
                "headerFontWeight: 'bold'"
                "})"
            )
        },
        "rowSelection": {"mode": "multiRow"},
    },
)

app.layout = dmc.MantineProvider(
    dmc.Group([dmc.Text("Theme Switch Demo"), theme_toggle, grid])
)

clientside_callback(
    """
    (n) => {
        document.documentElement.setAttribute(
            'data-mantine-color-scheme',
            (n % 2) ? 'dark' : 'light'
        );
        return window.dash_clientside.no_update;
    }
    """,
    Output("color-scheme-toggle", "id"),
    Input("color-scheme-toggle", "n_clicks"),
)

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