Note: Dash.NET is currently considered experimental. If your organization is interested in sponsoring Dash.NET, please get in touch.

Dash Layout

This is the 1st chapter of the Dash Fundamentals. The next chapter covers Dash callbacks.

This tutorial will walk you through a fundamental aspect of Dash apps, the app layout, through self-contained apps.

For production Dash apps, we recommend styling the app layout with Dash Enterprise Design Kit.


Dash apps are composed of two parts. The first part is the "layout", which describes what the app looks like. The second part describes the interactivity of the app and will be covered in the next chapter.

Note: Throughout this documentation,

F# code examples are meant to be saved as files and executed using dotnet fsi app.fsx You can also use Jupyter with the JupyterDash library.

If you're using Dash Enterprise's Data Science Workspaces, copy & paste the below code into your Workspace (see video).

Find out if your company is using Dash Enterprise

To get started, create a file named app.fsx , copy the code below into it, and then run it with dotnet fsi app.fsx.

// Run this app with `dotnet fsi app.fsx` and
// visit http://127.0.0.1:8050/ in your web browser.

#r "nuget: Dash.NET"
#r "nuget: Suave, 2.6.1"
#r "nuget: Suave.Experimental, 2.6.1"
#r "nuget: Dash.NET.Sauve"
#r "nuget: Plotly.NET"
#r "nuget: Feliz.Engine"
#r "nuget: Newtonsoft.Json, 13.0.1"

open Plotly.NET
open Dash.NET
open Dash.NET.Suave
open Dash.NET.DCC

let data =
    [ "SF", [ "Apples", 4; "Oranges", 1; "Bananas", 2 ]
      "Montr?al", [ "Apples", 2; "Oranges", 4; "Bananas", 5 ] ]

let fig =
    data
    |> List.map (fun (city, amts) -> Chart.Column(amts |> List.map fst, amts |> List.map snd, Name=city))
    |> Chart.Combine
    |> GenericChart.toFigure

let layout =
    Html.div [
        Attr.children [

            Html.h1 [ Attr.children "Hello Dash" ]

            Html.div [
                Attr.children """
                    Dash: A web application framework for your data.
                """
            ]

            Graph.graph "example-graph" [
                Graph.Attr.figure fig
            ]
        ]
    ]

DashApp.initDefault()
|> DashApp.withLayout layout
|> DashApp.run [||]
    { hostname = "localhost";
      ip = "127.0.0.1"
      port = 8050
      errorHandler = Suave.Web.defaultErrorHandler }

Hello Dash

Dash: A web application framework for your data.
c:\dash_net_app>dotnet fsi app.fsx
[20:42:13 INF] Smooth! Sauve listener started in 26.671ms with binding 127.0.0.1:8080

Visit http://127.0.0.1:8050/ in your web browser. You should see an app that looks like the one above.

Note:

  1. The layout is composed of a tree of "components" such as Html.div and Graph.
  2. The Dash.NET.Html module has a component for every HTML tag. The Html.h1 [ Attr.value "Hello Dash" ] component generates a <h1>Hello Dash</h1> HTML element in your app.
  3. Not all components are pure HTML. Dash.NET.DCC describe higher-level components that are interactive and are generated with JavaScript, HTML, and CSS through the React.js library. Dash.NET.DCC also has the AutoOpen attribute and do not require open Dash.NET.DCC.
  4. Each component is described entirely through keyword attributes. Dash is declarative: you will primarily describe your app through these attributes.
  5. The children property is special. By convention, it's always the first attribute . It can contain a string, a number, a single component, or a list of components.
  6. The fonts in your app will look a little bit different than what is displayed here. This app is using a custom CSS stylesheet and Dash Enterprise Design Kit to modify the default styles of the elements. You can learn more about custom CSS in the CSS tutorial.
  7. Dash.NET.Html does not have to be opened using open Dash.NET.Html for you to access their components. It is always available.

Making Your First Change

You can change the title "Hello Dash" in your app or change the x or y data. Save the file and restart the app to see your changes.

You can learn about tools to make debugging and developing Dash apps more productive and pleasant in Dash Dev Tools documentation

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.

More about HTML Components

Dash.NET.Html contains a component class for every HTML tag as well as keyword arguments for all of the HTML arguments.

Let's customize the text in our app by modifying the inline styles of the components. Create a file named app.fsx with the following code:

// Run this app with `dotnet fsi app.fsx` and
// visit http://127.0.0.1:8050/ in your web browser.

#r "nuget: Dash.NET"
#r "nuget: Suave, 2.6.1"
#r "nuget: Suave.Experimental, 2.6.1"
#r "nuget: Dash.NET.Sauve"
#r "nuget: Plotly.NET"
#r "nuget: Feliz.Engine"
#r "nuget: Newtonsoft.Json, 13.0.1"

open Plotly.NET
open Dash.NET
open Dash.NET.Suave
open Dash.NET.DCC

let colors =
    [ "background", "#111111"
      "text", "#7FDBFF" ]
    |> Map.ofList

let data =
    [ "SF", [ "Apples", 4; "Oranges", 1; "Bananas", 2 ]
      "Montréal", [ "Apples", 2; "Oranges", 4; "Bananas", 5 ] ]

let fig =
    data
    |> List.map (fun (city, amts) -> Chart.Column(amts |> List.map fst, amts |> List.map snd, Name=city))
    |> Chart.Combine
    |> Chart.withLayout(
        Layout.init(
            Plot_bgcolor = colors.["background"],
            Paper_bgcolor = colors.["background"],
            Font = Font.init(Color = colors.["text"])
        )
    )
    |> GenericChart.toFigure

let layout =
    Html.div [
        Attr.children [

            Html.h1 [
                Attr.children "Hello Dash"
                Attr.style [
                    StyleProperty ("textAlign", "center")
                    StyleProperty ("color", colors.["text"])
                ]
            ]

            Html.div [
                Attr.children "Dash: A web application framework for your data."
                Attr.style [
                    StyleProperty ("textAlign", "center")
                    StyleProperty ("color", colors.["text"])
                ]
            ]

            Graph.graph "example-graph" [
                Graph.Attr.figure fig
            ]
        ]
    ]

DashApp.initDefault()
|> DashApp.withLayout layout
|> DashApp.run [||]
    { hostname = "localhost";
      ip = "127.0.0.1"
      port = 8050
      errorHandler = Suave.Web.defaultErrorHandler }

Hello Dash

Dash: A web application framework for your data.

In this example, we modified the inline styles of the Html.div and Html.h1components with the Attr. style property.

Html.h1 [
    Attr.children "Hello Dash"
    Attr.style [
        StyleProperty ("textAlign", "center")
        StyleProperty ("color", "#7FDBFF")
    ]
]

The above code is rendered in the Dash app as <h1 style="text-align: center; color: #7FDBFF">Hello Dash</h1>.

There are a few important differences between the Dash.NET.Html and the HTML attributes:

  1. The style property in HTML is a semicolon-separated string. In Dash, you can just supply a list.
  2. The keys in the style list are camelCased. So, instead of text-align, it's textAlign.
  3. The HTML class attribute is className in Dash.
  4. The children of the HTML tag is specified through the children keyword argument. By convention, this is always the first argument .

Besides that, all of the available HTML attributes and tags are available to you within your F# context.


Reusable Components

By writing our markup in F#, we can create complex reusable components like tables without switching contexts or languages.

Here's a quick example that generates a Table from a FSharp.Data CSV. Create a file named app.fsx with the following code:

// Run this app with `dotnet fsi app.fsx` and
// visit http://127.0.0.1:8050/ in your web browser.

#r "nuget: Dash.NET"
#r "nuget: Suave, 2.6.1"
#r "nuget: Suave.Experimental, 2.6.1"
#r "nuget: Dash.NET.Sauve"
#r "nuget: Plotly.NET"
#r "nuget: Feliz.Engine"
#r "nuget: Newtonsoft.Json, 13.0.1"
#r "nuget: FSharp.Data"

open Dash.NET
open Dash.NET.Suave
open FSharp.Data

let maxRows = 10
let csv =
    CsvFile
        .Load("https://gist.githubusercontent.com/chriddyp/c78bf172206ce24f77d6363a2d754b59/raw/c353e8ef842413cae56ae3920b8fd78468aa4cb2/usa-agricultural-exports-2011.csv")
        .Cache()

let layout =
    Html.div [
        Attr.children [
            Html.h4 [ Attr.children "US Agriculture Exports (2011)" ]

            Html.table [
                Attr.children [
                    Html.thead [
                        csv.Headers
                        |> Option.map (Array.map (fun h -> Html.th [ Attr.children h ]))
                        |> Option.defaultValue [||]
                        |> Attr.children
                    ]
                    Html.tbody [
                        Attr.children (
                            csv.Rows
                            |> Seq.take maxRows
                            |> Seq.map (fun r ->
                                Html.tr [
                                    r.Columns
                                    |> Array.map (fun col -> Html.td [ Attr.children col ])
                                    |> Attr.children
                                ]
                            )
                        )
                    ]
                ]
            ]

        ]
    ]

DashApp.initDefault()
|> DashApp.withLayout layout
|> DashApp.run [||]
    { hostname = "localhost";
      ip = "127.0.0.1"
      port = 8050
      errorHandler = Suave.Web.defaultErrorHandler }

US Agriculture Exports (2011)

Unnamed: 0statetotal exportsbeefporkpoultrydairyfruits freshfruits proctotal fruitsveggies freshveggies proctotal veggiescornwheatcotton
0Alabama1390.6334.410.64814.06817.125.115.58.914.3334.970317.61
1Alaska13.310.20.100.190000.611.56000
2Arizona1463.1771.317.90105.4819.34160.27147.5239.4386.917.348.7423.95
3Arkansas3586.0253.229.4562.93.532.24.76.884.47.111.4569.5114.5665.44
4 California16472.88228.711.1225.4929.952791.85944.68736.4803.21303.52106.7934.6249.31064.95
5Colorado1851.33261.4661471.945.712.217.9945.173.2118.27183.2400.50
6Connecticut259.621.10.16.99.494.28.913.14.36.911.16000
7Delaware282.190.40.6114.72.30.511.537.612.420.0326.922.90
8Florida3764.0942.60.956.966.31438.2933.11371.36171.9279450.863.51.878.24
9Georgia2860.843118.9630.438.3874.6158.9233.515995.8154.7757.865.41154.07

More about Visualization

The Dash.NET.DCC module includes a component called Graph.

Graph Graph renders interactive data visualizations using the open source plotly.js JavaScript graphing library. Plotly.js supports over 35 chart types and renders charts in both vector-quality SVG and high-performance WebGL.

component is the same figure argument that is used by plotly.py, Plotly's open source graphing library. Check out the plotly.py documentation and gallery to learn more.

Here's an example that creates a scatter plot from a FSharp.Data CSV. Create a file named app.fsx with the following code:

// Run this app with `dotnet fsi app.fsx` and
// visit http://127.0.0.1:8050/ in your web browser.

#r "nuget: Dash.NET"
#r "nuget: Suave, 2.6.1"
#r "nuget: Suave.Experimental, 2.6.1"
#r "nuget: Dash.NET.Sauve"
#r "nuget: Plotly.NET"
#r "nuget: Feliz.Engine"
#r "nuget: Newtonsoft.Json, 13.0.1"
#r "nuget: FSharp.Data"

open Plotly.NET
open Dash.NET
open Dash.NET.Suave
open Dash.NET.DCC
open FSharp.Data

[<Literal>]
let Csv = "https://gist.githubusercontent.com/chriddyp/5d1ea79569ed194d432e56108a04d188/raw/a9f9e8076b837d541398e999dcbac2b2826a81f8/gdp-life-exp-2007.csv"
type CsvData = CsvProvider<Csv>
let csv = CsvData.Load(Csv).Cache()
let toLabel (r:CsvData.Row) =
    sprintf "<br>%s=%s<br>%s=%s<br>%s=%.3f"
        (nameof(r.Country))
        r.Country
        (nameof(r.Continent))
        r.Continent
        (nameof(r.Population))
        r.Population


let fig =
    let refRow = csv.Rows |> Seq.head

    Chart.Bubble(
        csv.Rows |> Seq.map (fun r -> r.``Gdp per capita``),
        csv.Rows |> Seq.map (fun r -> r.``Life expectancy``),
        csv.Rows |> Seq.map (fun r -> r.Population / (decimal 10_000_000)),
        Labels = (csv.Rows |> Seq.map toLabel)
    )
    |> Chart.withX_Axis(
        Axis.LinearAxis.init(
            AxisType = StyleParam.AxisType.Log,
            Title = nameof(refRow.``Gdp per capita``)
        )
    )
        |> Chart.withY_Axis(
            Axis.LinearAxis.init(
                Title = nameof(refRow.``Life expectancy``)
            )
        )
    |> GenericChart.toFigure

let layout =
    Html.div [
        Attr.children [
            Graph.graph "life-exp-vs-gdp" [
                Graph.Attr.figure fig
            ]
        ]
    ]

DashApp.initDefault()
|> DashApp.withLayout layout
|> DashApp.run [||]
    { hostname = "localhost";
      ip = "127.0.0.1"
      port = 8050
      errorHandler = Suave.Web.defaultErrorHandler }
2345678910002345678910k234564050607080
continentAsiaEuropeAfricaAmericasOceaniagdp per capitalife expectancy

These graphs are interactive and responsive. Hover over points to see their values, click on legend items to toggle traces, click and drag to zoom, hold down shift, and click and drag to pan.

Markdown

While Dash exposes HTML through Dash.NET.Html, it can be tedious to write your copy in HTML. For writing blocks of text, you can use the Markdown component in Dash.NET.DCC. Create a file named app.fsx with the following code:

// Run this app with `dotnet fsi app.fsx` and
// visit http://127.0.0.1:8050/ in your web browser.

#r "nuget: Dash.NET"
#r "nuget: Suave, 2.6.1"
#r "nuget: Suave.Experimental, 2.6.1"
#r "nuget: Dash.NET.Sauve"
#r "nuget: Plotly.NET"
#r "nuget: Feliz.Engine"
#r "nuget: Newtonsoft.Json, 13.0.1"

open Dash.NET
open Dash.NET.Suave
open Dash.NET.DCC

let layout =
    Markdown.markdown "markdown" [
        Markdown.Attr.children """
            ### Dash and Markdown

            Dash apps can be written in Markdown.
            Dash uses the [CommonMark](http://commonmark.org/)
            specification of Markdown.
            Check out their [60 Second Markdown Tutorial](http://commonmark.org/help/)
            if this is your first introduction to Markdown!
        """
    ]

DashApp.initDefault()
|> DashApp.withLayout layout
|> DashApp.run [||]
    { hostname = "localhost";
      ip = "127.0.0.1"
      port = 8050
      errorHandler = Suave.Web.defaultErrorHandler }

Dash and Markdown

Dash apps can be written in Markdown. Dash uses the CommonMark specification of Markdown. Check out their 60 Second Markdown Tutorial if this is your first introduction to Markdown!

Core Components

Dash.NET.DCC includes a set of higher-level components like dropdowns, graphs, markdown blocks, and more.

Like all Dash components, they are described entirely declaratively. Every option that is configurable is available as a keyword argument of the component.

We'll see many of these components throughout the tutorial. You can view all of the available components in the Dash Core Components overview.

Here are a few of the available components. Create a file named app.fsx with the following code:

// Run this app with `dotnet fsi app.fsx` and
// visit http://127.0.0.1:8050/ in your web browser.

#r "nuget: Dash.NET"
#r "nuget: Suave, 2.6.1"
#r "nuget: Suave.Experimental, 2.6.1"
#r "nuget: Dash.NET.Sauve"
#r "nuget: Plotly.NET"
#r "nuget: Feliz.Engine"
#r "nuget: Newtonsoft.Json, 13.0.1"

open Dash.NET
open Dash.NET.Suave
open Dash.NET.DCC

let layout =
    Html.div [
        Attr.children [
            Html.label [ Attr.children "Dropdown" ]
            Dropdown.dropdown "dropdown" [
                Dropdown.Attr.options [
                    { Label = "New York City"; Value = "NYC"; Disabled = false; Title = "New York City" }
                    { Label = "Montréal"; Value = "MTL"; Disabled = false; Title = "Montréal" }
                    { Label = "San Francisco"; Value = "SF"; Disabled = false; Title = "San Francisco" }
                ]
                Dropdown.Attr.value "MTL"
            ]

            Html.label [ Attr.children "Multi-Select Dropdown" ]
            Dropdown.dropdown "multi-select-dropdown" [
                Dropdown.Attr.options [
                    { Label = "New York City"; Value = "NYC"; Disabled = false; Title = "New York City" }
                    { Label = "Montréal"; Value = "MTL"; Disabled = false; Title = "Montréal" }
                    { Label = "San Francisco"; Value = "SF"; Disabled = false; Title = "San Francisco" }
                ]
                Dropdown.Attr.value "MTL"
                Dropdown.Attr.multi true
            ]

            Html.label [ Attr.children "Radio Items" ]
            RadioItems.radioItems "radioitems" [
                RadioItems.Attr.options [
                    { Label = "New York City"; Value = "NYC"; Disabled = false }
                    { Label = "Montréal"; Value = "MTL"; Disabled = false }
                    { Label = "San Francisco"; Value = "SF"; Disabled = false }
                ]
                RadioItems.Attr.value "MTL"
            ]

            Html.label [ Attr.children "Checkboxes" ]
            Checklist.checklist "checkboxes" [
                Checklist.Attr.options [
                    { Label = "New York City"; Value = "NYC"; Disabled = false }
                    { Label = "Montréal"; Value = "MTL"; Disabled = false }
                    { Label = "San Francisco"; Value = "SF"; Disabled = false }
                ]
                Checklist.Attr.value [ "MTL"; "SF" ]
            ]

            Html.label [ Attr.children "Text Input" ]
            Input.input "text-input" [
                Input.Attr.inputType InputType.Text
                Input.Attr.value "MTL"
            ]

            Html.label [ Attr.children "Slider" ]
            Slider.slider "slider" [
                Slider.Attr.min 0
                Slider.Attr.max 9
                Slider.Attr.marks
                    ([ for i in 1..5 ->
                        string i,
                        Slider.MarkValue.String <| match i with 1 -> sprintf "Label %i" i | _ -> string i ]
                     |> Map.ofList
                     |> Slider.MarksType)
                Slider.Attr.value 5
            ]
        ]
        Attr.style [ StyleProperty ("columnCount", "2") ]
    ]

DashApp.initDefault()
|> DashApp.withLayout layout
|> DashApp.run [||]
    { hostname = "localhost";
      ip = "127.0.0.1"
      port = 8050
      errorHandler = Suave.Web.defaultErrorHandler }
Montréal
×

Montréal 
San Francisco 
×



Label 12345

Help

Dash components are declarative: every configurable aspect of these components is set during instantiation as a keyword argument.

On any component you can hover over the function in your IDE to learn more about a component and its available arguments.

E.g. hovering over dropdown function in Dropdown.dropdown: dropdown

Summary

The layout of a Dash app describes what the app looks like. The layout is a hierarchical tree of components, or a list of components (in Dash 2.17 and later).

The Dash.NET.Html module provides classes for all of the HTML tags and the keyword arguments describe the HTML attributes like style, class, and id. The Dash.NET.DCC module generates higher-level components like controls and graphs.

For reference, see:

The next part of the Dash Fundamentals covers how to make these apps interactive. Dash Fundamentals Part 2: Basic Callbacks