Dash AG Grid change font color of headerName based on condition

Hi, I’m creating a AG Grid with grouped columns like shown below.
I want now to change the font color of the headerName of the group title if the headerName value is included in the “important” array.
So in the example below only the header “Values” should be in a different color.

Any advise how to implement the condition function properly?

from dash import Dash, html
import dash_ag_grid as dag
import pandas as pd


def create_table():
    df = pd.DataFrame({
        "Setup_A": (
            1, 1, 1, 2, 2, 2, 3, 3, 3,
        ),
        "Setup_B": (
            1, 2, 3, 1, 2, 3, 1, 2, 3, 
        ),
        "Values_A": (
            68, 69, 67, 68, 69, 67, 68, 69, 67,
        ),
        "Values_B": (
            55, 43, 49, 49, 42, 48, 46, 41, 50,
        ),
        "Infos_A" : (
            "A", "A", "A", "B", "B", "B", "A", "A", "A"
        ),
        "Infos_B" : (
            "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG"
        )
    })

    header = ["Setup", "Values", "Infos"]
    important = ["Values"]

    columnDefs = [
        {
            "headerName": head,
            "cellStyle" : {
                "styleConditions" : [
                    {
                        "condition" : f"{important}.includes(params.value)",
                        "style" : {"color" : 'rgb(253, 253, 20)'}
                    }
                ]
            },
            "children": [
                {"headerName": "A", "field": f"{head}_A"},
                {"headerName": "B", "field": f"{head}_B"},
            ],
        } for head in header
    ]

    grid = dag.AgGrid(
        id="column-groups-basic",
        rowData=df.to_dict("records"),
        columnDefs=columnDefs,
        defaultColDef={"resizable": True},
        style={"height": "600px"}
    ),

    return grid


app = Dash(__name__)

table = create_table()

app.layout = html.Div(
    table
)

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

Hi @Bakira

In order to style the group header, you can use a function to add a CSS class to the header. Use the headerClass prop in the defaultColGroupDef prop. See the example below.

If you also want to style each column header, you can do something similar using the defaultColDef.

Note that if you dynamically update list of columns to style, you may also have to refresh the headers using params.api.refreshHeader(); You can see an example of the clientside callback in this post


from dash import Dash, html
import dash_ag_grid as dag
import pandas as pd


def create_table():
    df = pd.DataFrame({
        "Setup_A": (
            1, 1, 1, 2, 2, 2, 3, 3, 3,
        ),
        "Setup_B": (
            1, 2, 3, 1, 2, 3, 1, 2, 3,
        ),
        "Values_A": (
            68, 69, 67, 68, 69, 67, 68, 69, 67,
        ),
        "Values_B": (
            55, 43, 49, 49, 42, 48, 46, 41, 50,
        ),
        "Infos_A" : (
            "A", "A", "A", "B", "B", "B", "A", "A", "A"
        ),
        "Infos_B" : (
            "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG"
        )
    })

    header = ["Setup", "Values", "Infos"]
    important = ["Values"]

    columnDefs = [
        {
            "headerName": head,
            "children": [
                {"headerName": "A", "field": f"{head}_A"},
                {"headerName": "B", "field": f"{head}_B"},
            ],
        } for head in header
    ]
   

    grid = dag.AgGrid(
        id="column-groups-basic",
        rowData=df.to_dict("records"),
        columnDefs=columnDefs,
        defaultColDef={"resizable": True},
        dashGridOptions={"defaultColGroupDef": {'headerClass': {'function': f'importantColumn(params, {important})'}}},
        style={"height": "600px"}
    ),

    return grid


app = Dash(__name__)

table = create_table()

app.layout = html.Div(
    table
)

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


'''
// Add the following to a  .css file in /assets

.important-column {
  color: red;
}
-----------------

// Add the following the the dashAgGridFunctions.js file in /assets



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

dagfuncs.importantColumn = (params, important) => {  
  if (important.includes(params.colDef.headerName)) {
    return 'important-column'} else { return ''}
  }

'''
2 Likes

Hi @AnnMarieW ,

thanks for your great help and sorry for the late reply.

I could follow your advice and it basically works as expected. But as you already noted, the “important” array is created dynamically in the later application. As you suggested I tried to implement the clientside callback from the linked post. I ended up with following example.
Any idea why the colors are only updated after adding a new column?

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


def create_layout(app):
    app.clientside_callback(
        """    
        function (id) {
            dash_ag_grid.getApiAsync(id).then((grid) =>
                grid.addEventListener("newColumnsLoaded", (params) => {
                    params.api.refreshHeader();
                }),
            );
            return dash_clientside.no_update
        }
        """,
        Output('table', 'id'),
        Input('table', 'id')
    )

    @app.callback(
        Output("table", "children"),
        Input("dropdown", "value")
    )
    def create_table(value):
        df = pd.DataFrame({
            "Setup_A": (
                1, 1, 1, 2, 2, 2, 3, 3, 3,
            ),
            "Setup_B": (
                1, 2, 3, 1, 2, 3, 1, 2, 3, 
            ),
            "Values_A": (
                68, 69, 67, 68, 69, 67, 68, 69, 67,
            ),
            "Values_B": (
                55, 43, 49, 49, 42, 48, 46, 41, 50,
            ),
            "Infos_A" : (
                "A", "A", "A", "B", "B", "B", "A", "A", "A"
            ),
            "Infos_B" : (
                "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG"
            ),
            "Orient_A" : (
                "Left", "Left", "Left", "Left", "Left", "Left", "Left", "Left", "Left"
            ),
            "Orient_B" : (
                "Right", "Right", "Right", "Right", "Right", "Right", "Right", "Right", "Right"
            )
        })

        header = ["Setup", "Values", "Infos", "Orient"]

        columnDefs = [
            {
                "headerName": head,
                "children": [
                    {"headerName": "A", "field": f"{head}_A"},
                    {"headerName": "B", "field": f"{head}_B"},
                ],
            } for head in header
        ]

        grid = dag.AgGrid(
            id="column-groups-basic",
            rowData=df.to_dict("records"),
            columnDefs=columnDefs,
            defaultColDef={"resizable": True},
            dashGridOptions={"defaultColGroupDef": {'headerClass': {'function': f'importantColumn(params, {value})'}}},
            style={"height": "600px"}
        ),

        return grid


    return html.Div(children=[
        dcc.Dropdown(
            options= ["Values", "Infos"],
            placeholder="Important",
            id='dropdown',
            multi=True
        ),
        html.Div(children=[

        ],
        id="table")
    ])

def main() -> None:
    app = Dash()
    app.layout = create_layout(app)
    app.run_server(debug=True, port=8050)


if __name__ == "__main__":
    main()

with .css:

.important-column {
    color: red;
  }

.notimportant-column {
  color: rgb(0, 0, 0);
}

and .js:

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

dagfuncs.importantColumn = (params, important) => {  
  if (important.includes(params.colDef.headerName)) {
    return 'important-column'} else { return 'notimportant-column'}
}

Hi @Bakira

Try the example below It’s yet another awesome solution from @jinnyzor


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


def create_table():
    df = pd.DataFrame({
        "Setup_A": (
            1, 1, 1, 2, 2, 2, 3, 3, 3,
        ),
        "Setup_B": (
            1, 2, 3, 1, 2, 3, 1, 2, 3,
        ),
        "Values_A": (
            68, 69, 67, 68, 69, 67, 68, 69, 67,
        ),
        "Values_B": (
            55, 43, 49, 49, 42, 48, 46, 41, 50,
        ),
        "Infos_A": (
            "A", "A", "A", "B", "B", "B", "A", "A", "A"
        ),
        "Infos_B": (
            "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG", "DAG"
        )
    })

    header = ["Setup", "Values", "Infos"]

    columnDefs = [
        {
            "headerName": head,
            "children": [
                {"headerName": "A", "field": f"{head}_A"},
                {"headerName": "B", "field": f"{head}_B"},
            ],
        } for head in header
    ]

    grid = dag.AgGrid(
        id="grid",
        rowData=df.to_dict("records"),
        columnDefs=columnDefs,
        defaultColDef={"resizable": True},
        dashGridOptions={"defaultColGroupDef": {'headerClass': {'function': f'importantColumns(params)'}}},
        style={"height": "600px"}
    )

    return grid


app = Dash(__name__)

table = create_table()

dropdown =  dcc.Dropdown(
    options= ["Values", "Infos", "Setup"],
    placeholder="Important",
    id='dropdown',
    multi=True
)

app.layout = html.Div([
    dropdown,
    table
])


clientside_callback(
    """function (v, id) {
        window.important = v
        dash_ag_grid.getApiAsync(id).then((grid) => {grid.refreshHeader();})  
        return dash_clientside.no_update
    }""",
    Output("dropdown", "id"),
    Input("dropdown", "value"),
    State('grid', 'id'),
    prevent_initial_call=True,
)


if __name__ == "__main__":
    app.run(debug=True)
    
    
    
'''
// Add the following to a  .css file in /assets

.important-column {
  color: red;
}
-----------------

// Add the following the the dashAgGridFunctions.js file in /assets



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


dagfuncs.importantColumns = (params) => {
  if ((window.important || []).includes(params.colDef.headerName)) {
    return 'important-column'
    } else { return ''}
  }


'''
1 Like

Hi @AnnMarieW,

works like a charm. Thanks for your help!

1 Like

Hi @AnnMarieW ,

I used your solution, and it works perfectly when I set dashGridOptions. However, I noticed that the header color doesn’t change when I set the className for the AG Grid. Is there any way to prevent the dashGridOptions from being overwritten by the class settings?

grid = dag.AgGrid(
    id="grid",
    rowData=df.to_dict("records"),
    columnDefs=columnDefs,
    defaultColDef={"resizable": True},
    dashGridOptions={"defaultColGroupDef": {'headerClass': {'function': f'importantColumns(params)'}}},
    className='ag-theme-balham',
    style={"height": "600px"}
)

Thank you in advance.

Hello @wen,

I’m not sure what you mean by overridden? Could you please elaborate?

2 posts were split to a new topic: Dash AG Grid Single Header with Different Colors