# Styling the DataTable

## Default Styles

By default, the DataTable has grey headers and borders around each cell. It resembles a spreadsheet and the headers are clearly defined.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)]

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## Column Alignment

When displaying numerical data, it's a good practice to use monospaced fonts, to right-align the data, and to provide the same number of decimals throughout the column.

> To learn about formatting numbers and dates, see Typing.

For textual data, left-aligning the text is usually easier to read.

In both cases, the column headers should have the same alignment as the cell content.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)],
        style_cell=Dict("textAlign" =>  "left"),
        style_cell_conditional=[
            Dict(
                "if" =>  Dict("column_id" =>  "Region"),
                "textAlign" =>  "left"
            )
        ]

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## Styling the Table as a List

The gridded view is a good default view for an editable table as it looks and feels like a spreadsheet. If your table isn't editable, then in many cases it can look cleaner without the vertical grid lines.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)],
        style_cell_conditional=[
            Dict(
                "if" =>  Dict("column_id" =>  c),
                "textAlign" =>  "left"
            ) for c in ["Date", "Region"]
        ],

        style_as_list_view=true,

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## List Style with Minimal Headers

In some contexts, the grey background can look a little heavy. You can lighten this up by giving it a white background and a bold text.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)],
        style_as_list_view=true,
        style_cell=Dict("padding" =>  "5px"),
        style_header=Dict(
            "backgroundColor" =>  "white",
            "fontWeight" =>  "bold"
        ),
        style_cell_conditional=[
            Dict(
                "if" =>  Dict("column_id" =>  c),
                "textAlign" =>  "left"
            ) for c in ["Date", "Region"]
        ],

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## Striped Rows

When you're viewing datasets where you need to compare values within individual rows, it can sometimes be helpful to give the rows alternating background colors. We recommend using colors that are faded so as to not attract too much attention to the stripes.

Sign up for Dash Club → Two free cheat sheets plus updates from Chris Parmer and Adam Schroeder delivered to your inbox every two months. Includes tips and tricks, community apps, and deep dives into the Dash architecture. Join now.

Notice the three different groups you can style: "cell" is the whole table, "header" is just the header rows, and "data" is just the data rows. To use even/odd or other styling based on `row_index` you must use `style_data_conditional`.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)],
        style_cell_conditional=[
            Dict(
                "if" =>  Dict("column_id" =>  c),
                "textAlign" =>  "left"
            ) for c in ["Date", "Region"]
        ],
        style_data_conditional=[
            Dict(
                "if" =>  Dict("row_index" =>  "odd"),
                "backgroundColor" =>  "rgb(248, 248, 248)"
            )
        ],
        style_header=Dict(
            "backgroundColor" =>  "rgb(230, 230, 230)",
            "fontWeight" =>  "bold"
        )

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## Multi-Headers

Multi-headers are natively supported in the `DataTable`. Just set `name` inside `columns` as a list of strings instead of a single string and toggle `merge_duplicate_headers=True`. `DataTable` will check the neighbors of each header row and, if they match, will merge them into a single cell automatically.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
      columns=[
        Dict("name" =>  ["", "Year"], "id" =>  "year"),
        Dict("name" =>  ["City", "Montreal"], "id" =>  "montreal"),
        Dict("name" =>  ["City", "Toronto"], "id" =>  "toronto"),
        Dict("name" =>  ["City", "Ottawa"], "id" =>  "ottawa"),
        Dict("name" =>  ["City", "Vancouver"], "id" =>  "vancouver"),
        Dict("name" =>  ["Climate", "Temperature"], "id" =>  "temp"),
        Dict("name" =>  ["Climate", "Humidity"], "id" =>  "humidity"),
    ],
    data=[
        Dict(
            "year" =>  i,
            "montreal" =>  i * 10,
            "toronto" =>  i * 100,
            "ottawa" =>  i * -1,
            "vancouver" =>  i * -10,
            "temp" =>  i * -100,
            "humidity" =>  i * 5,
        )
        for i in 1:10
    ],
    merge_duplicate_headers=true,

    )

    run_server(app, "0.0.0.0", debug=true)

| City | Climate
--- | --- | ---
Year | Montreal | Toronto | Ottawa | Vancouver | Temperature | Humidity
0 | 0 | 0 | 0 | 0 | 0 | 0
1 | 10 | 100 | -1 | -10 | -100 | 5
2 | 20 | 200 | -2 | -20 | -200 | 10
3 | 30 | 300 | -3 | -30 | -300 | 15
4 | 40 | 400 | -4 | -40 | -400 | 20
5 | 50 | 500 | -5 | -50 | -500 | 25
6 | 60 | 600 | -6 | -60 | -600 | 30
7 | 70 | 700 | -7 | -70 | -700 | 35
8 | 80 | 800 | -8 | -80 | -800 | 40
9 | 90 | 900 | -9 | -90 | -900 | 45

## Dark Theme with Cells

You have full control over all of the elements in the table. If you are viewing your table in an app with a dark background, you can provide inverted background and font colors.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)],
        style_header=Dict("backgroundColor" =>  "rgb(30, 30, 30)"),
        style_cell=Dict(
            "backgroundColor" =>  "rgb(50, 50, 50)",
            "color" =>  "white"
        ),

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## Conditional Formatting

See the new conditional formatting chapter.

## Styles Priority

There is a specific order of priority for the `style_*` properties. If there are multiple `style_*` props, the one with higher priority will take precedence. Within each prop, rules for higher indices will be prioritized over those for lower indices. Previously applied styles of equal priority win over later ones (applied top to bottom, left to right).

These are the priorities of `style_*` props, in decreasing order:

1. `style_data_conditional`
2. `style_data`
3. `style_filter_conditional`
4. `style_filter`
5. `style_header_conditional`
6. `style_header`
7. `style_cell_conditional`
8. `style_cell`

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)],
        style_header=Dict( "border" =>  "1px solid black" ),
        style_cell=Dict( "border" =>  "1px solid grey" ),

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## Adding Borders

Customize the table borders by adding `border` to `style_*` props.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c) for c in names(df)],
        style_data=Dict( "border" =>  "1px solid blue" ),
        style_header=Dict( "border" =>  "1px solid pink" ),

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15

## Styling Editable Columns

Editable columns can be styled using `column_editable` in `style_header_conditional`, `style_filter_conditional`, and `style_data_conditional` props.

    using Dash
    using OrderedCollections, DataFrames

    data = OrderedDict(
          "Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
          "Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
          "Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
          "Humidity" => [10, 20, 30, 40, 50, 60],
          "Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
    )

    df = DataFrame(data)

    app = dash()

    app.layout = dash_datatable(
        data = map(eachrow(df)) do r
          Dict(names(r) .=> values(r))
        end,
        columns=[Dict("name" =>c, "id" => c, "editable" => (c == "Humidity")) for c in names(df)],
        style_data_conditional=[Dict(
            "if" =>  Dict("column_editable" =>  false),
            "backgroundColor" =>  "rgb(30, 30, 30)",
            "color" =>  "white"
        )],
        style_header_conditional=[Dict(
            "if" =>  Dict("column_editable" =>  false),
            "backgroundColor" =>  "rgb(30, 30, 30)",
            "color" =>  "white"
        )],

    )

    run_server(app, "0.0.0.0", debug=true)

Date | Region | Temperature | Humidity | Pressure
--- | --- | --- | --- | ---
2015-01-01 | Montreal | 1 | 10 | 2
2015-10-24 | Toronto | -20 | 20 | 10924
2016-05-10 | New York City | 3.512 | 30 | 3912
2017-01-10 | Miami | 4 | 40 | -10
2018-05-10 | San Francisco | 10423 | 50 | 3591.2
2018-08-15 | London | -441.2 | 60 | 15