# Getting Started

<div align="center"><figure><img src="/files/qscxk3O4aXW6jLiuNsnA" alt=""><figcaption><p>Screenshot of the example app. (Simple counter app with a text block and two buttons)</p></figcaption></figure></div>

## Step 1: Empty Console App

Create a new F# console application targeting .net 8 or higher.

## Step 2: Packages

Reference the following packages [Avalonia.Desktop](https://www.nuget.org/packages/Avalonia.Desktop/12.1.0), [Avalonia.Themes.Fluent](https://www.nuget.org/packages/Avalonia.Themes.Fluent/12.1.0) and [Avalonia.FuncUI](https://www.nuget.org/packages/Avalonia.FuncUI/2.0.0).

{% tabs %}
{% tab title="dotnet CLI" %}
Run the following commands in your project directory:

```bash
dotnet add package Avalonia.Desktop --version 12.1.0
dotnet add package Avalonia.Themes.Fluent --version 12.1.0
dotnet add package Avalonia.FuncUI --version 2.0.0
```

{% endtab %}

{% tab title="edit Project file" %}
Paste the following package references to your fsproject file:

```html
<PackageReference Include="Avalonia.Desktop" Version="12.1.0" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.1.0" />
<PackageReference Include="Avalonia.FuncUI" Version="2.0.0" />
```

{% endtab %}
{% endtabs %}

## Step 3: Add code to `Program.fs`

```fsharp
namespace CounterApp

open Avalonia
open Avalonia.Controls.ApplicationLifetimes
open Avalonia.Themes.Fluent
open Avalonia.FuncUI.Hosts
open Avalonia.Controls
open Avalonia.FuncUI
open Avalonia.FuncUI.DSL
open Avalonia.Layout

module Main =

    let view () =
        Component(fun ctx ->
            let state = ctx.useState 0

            DockPanel.create [
                DockPanel.children [
                    Button.create [
                        Button.dock Dock.Bottom
                        Button.onClick (fun _ -> state.Set(state.Current - 1))
                        Button.content "-"
                        Button.horizontalAlignment HorizontalAlignment.Stretch
                        Button.horizontalContentAlignment HorizontalAlignment.Center
                    ]
                    Button.create [
                        Button.dock Dock.Bottom
                        Button.onClick (fun _ -> state.Set(state.Current + 1))
                        Button.content "+"
                        Button.horizontalAlignment HorizontalAlignment.Stretch
                        Button.horizontalContentAlignment HorizontalAlignment.Center
                    ]
                    TextBlock.create [
                        TextBlock.dock Dock.Top
                        TextBlock.fontSize 48.0
                        TextBlock.verticalAlignment VerticalAlignment.Center
                        TextBlock.horizontalAlignment HorizontalAlignment.Center
                        TextBlock.text (string state.Current)
                    ]
                ]
            ]
        )

type MainWindow() =
    inherit HostWindow()
    do
        base.Title <- "Counter Example"
        base.Content <- Main.view ()

type App() =
    inherit Application()

    override this.Initialize() =
        this.Styles.Add (FluentTheme())
        this.RequestedThemeVariant <- Styling.ThemeVariant.Dark

    override this.OnFrameworkInitializationCompleted() =
        match this.ApplicationLifetime with
        | :? IClassicDesktopStyleApplicationLifetime as desktopLifetime ->
            desktopLifetime.MainWindow <- MainWindow()
        | _ -> ()

module Program =

    [<EntryPoint>]
    let main(args: string[]) =
        AppBuilder
            .Configure<App>()
            .UsePlatformDetect()
            .UseSkia()
            .StartWithClassicDesktopLifetime(args)

```

## Step 4: build and run 🎉

```bash
dotnet run
```


# View Basics

FuncUI comes with a DSL to describe views and their attributes.&#x20;

```fsharp
DockPanel.create [
    DockPanel.children [
        Button.create [
            Button.dock Dock.Bottom
            Button.onClick (fun _ -> state.Current - 1 |> state.Set)
            Button.content "-"
            Button.horizontalAlignment HorizontalAlignment.Stretch
        ]
        Button.create [
            Button.dock Dock.Bottom
            Button.onClick (fun _ -> state.Current + 1 |> state.Set)
            Button.content "+"
            Button.horizontalAlignment HorizontalAlignment.Stretch
        ]
        TextBlock.create [
            TextBlock.dock Dock.Top
            TextBlock.fontSize 48.0
            TextBlock.verticalAlignment VerticalAlignment.Center
            TextBlock.horizontalAlignment HorizontalAlignment.Center
            TextBlock.text (string state.Current)
        ]
    ]
]
```


# Creating views

There are multiple ways of creating a view for a certain control. They all have in common that the resulting type is `IView` or `IView<'t>`.

## Creating views for common controls

FuncUI provides functions for creating standard Avalonia controls. The create function always follows the same pattern.\\

<pre class="language-fsharp" data-title="internal - signature"><code class="lang-fsharp"><strong>module Button =
</strong><strong>    val create: attrs: IAttr&#x3C;'control> list -> IView&#x3C;'control>
</strong></code></pre>

{% code title="user code" %}

```fsharp
Button.create [
    // view attributes
]
```

{% endcode %}

{% hint style="success" %}
The create function is always found on the module named the same as the Avalonia control.

So the create function for a `TextBlock` is `TextBlock.create`, for a `StackPanel` it's `StackPanel.create` and so on.
{% endhint %}

## Creating views for custom controls

Even without creating bindings for a control you can create and embed it in a view.

```fsharp
View.createGeneric<MyCustomControl> [
    // view attributes
]
```

### Passing constructor arguments

Sometimes controls don't have a unit constructor and need constructor arguments. Here is how you can pass them.

```fsharp
[
    // view attributes
]
|> View.createGeneric<MyCustomControl> 
|> View.withConstructorArgs [| "constructorArg1" :> obj; "constructorArg2" :> obj |]
    

```


# Lifetime

Every FuncUI view is backed by an Avalonia Control. Even when attributes of a view change, the backing control does not change. Instead, changes are mirrored to the backing Control. This is often called "patching".

<img src="/files/UQ1PA4iLAr3SZQIJInPx" alt="" class="gitbook-drawing">

Views don't hold a reference to their backing Avalonia control. The backing control is determined by the view structure.

<img src="/files/LfIh43CBPFvcotHTAdqK" alt="" class="gitbook-drawing">

This means if the structure changes the backing control also does change. FuncUI will ensure the new backing control is patched / has all attributes set as specified in the view.

If the view type in the structure does not match the view type in the backing structure a new backing control is created.

<img src="/files/vORLtwKKFOfRsuYXb1eB" alt="" class="gitbook-drawing">

{% hint style="info" %}
Only backing views of the same type can be reused when the view structure changes.
{% endhint %}

## Keyed Views

Sometimes you need more control over the reuse of backing controls. This can be achieved by specifying a view key.\
\
If the view key changes a new backing view is created, no patching is attempted.

```fsharp
[ 
    // View attributes
]
|> Button.create
|> View.withKey "button-1"
```

```fsharp
View.createWithKey "button-1" Button.create [
    // View attributes
]
```


# Attributes

### 🔧 Properties

For each .NET Property defined on an Avalonia Control there is a corresponding Attribute. Most of them are Property Attributes, but not all of them.

```fsharp
Button.create [
    Button.margin 5.0
    Button.content "button text"
]
...
```

### ⚡ Events

Events are just like other attributes. You can easily recognize them by their prefix. Events are named like this

> **{ControlName}**.on\*\*{EventName}\*\*

```fsharp
Button.onClick (fun args -> // do something )
TextBox.onKeyDown (fun args -> // do something )
TextBox.onKeyUp (fun args -> // do something )
ListBox.onSelectionChanged (fun args -> // do something )
...
```

When subscribing to an event you can also provide `SubPatchOptions` to configure when the subscription will be updated. If your handler function captures state you will run into issues if your handler captures state you'd expect to change.\
\
In the example below the handler function captures `current` . When the button is clicked we update the state with current + 1 but the value of `current` in our handler function **never changes**.

<figure><img src="/files/UyVbEStUbpqSaEbLpB4c" alt=""><figcaption></figcaption></figure>

Capturing state that changes over time should be avoided in most cases. You can provide FuncUI with a way of knowing when to update your handler function.\
\
Update handler function on render if current value changed:

```fsharp
Button.onClick (
    func = (fun _ -> state.Set (current + 1)),
    subPatchOptions = SubPatchOptions.OnChangeOf current
)
```

Update handler function on each render pass:

```fsharp
Button.onClick (
    func = (fun _ -> state.Set (current + 1)),
    subPatchOptions = SubPatchOptions.Always
)
```

By default, the handler function is only updated if the underlying delegate type changes.

### 🧲 Attached Properties

Attached Attributes are used like Events and normal Properties.

> **{ControlName}**.**{name}**

```fsharp
StackPanel.dock Dock.Top
StackPanel.row 1
StackPanel.column 1
...
```

> ⚠ Currently not all attached properties are supported / declared. This is currently in process, feel free to create an issue if something is missing

### 📦 Content Properties

Content Properties are attributes containing either a single View or a list of Views. They are often named `content`, `children`, `viewItems`, … you get it.

Here are some examples.

```fsharp
// single view content
Button.create [
    // takes 'View'
    Button.content (
        TextBlock.create [
            TextBlock.text "some text"
        ]
    )
]

// content view list
StackPanel.create [
    // takes 'View list'
    StackPanel.children [
        TextBox.create [
            TextBox.text "one"
        ]
        TextBox.create [
            TextBox.text "two"
        ]
        ...
    ]
]
```


# How to create bindings

Creating bindings for Avalonia controls is fairly easy. You just need to know a little bit about the source of the control and its public properties/events.

You can create bindings for any public styled/direct properties for example the `IsPressed` [Property of Button.cs](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Controls/Button.cs#L78)

```csharp
public static readonly StyledProperty<bool> IsPressedProperty = 
    AvaloniaProperty.Register<Button, bool>(nameof(IsPressed));
```

In the case of an event, the event should be a `RoutedEvent` for example the [ClickEvent of Button.cs](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Controls/Button.cs#L75)

```csharp
/// <summary>
/// Defines the <see cref="Click"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> ClickEvent =
    RoutedEvent.Register<Button, RoutedEventArgs>(nameof(Click), RoutingStrategies.Bubble);
```

That's all we need to know before we start creating a binding. To create bindings like Avalonia.FuncUI ones, we need to define a module with the name of the control and add two things, a `create` function and *augment* the existing control with some static methods.

Let's check [Button.fs](https://github.com/AvaloniaCommunity/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI.DSL/Button.fs) in Avalonia.FuncUI.source code

```fsharp
[<AutoOpen>]
module Button =
    (* omitting the other existing open statements for clarity *)
    open Avalonia.Controls
    open Avalonia.FuncUI.Builder
    open Avalonia.FuncUI.Types
    (* omitting the other existing open statements for clarity *)

    let create(attrs: IAttr<Button> list): IView<Button> =
        ViewBuilder.Create<Button>(attrs)

    type Button with 
        (* omitting the other existing bindings for clarity *)

        static member isPressed<'t when 't :> Button>(value: bool) : IAttr<'t> =
            AttrBuilder<'t>.CreateProperty<bool>(Button.IsPressedProperty, value, ValueNone)

        static member onClick<'t when 't :> Button>(func: RoutedEventArgs -> unit, ?subPatchOptions) =
            AttrBuilder<'t>.CreateSubscription<RoutedEventArgs>(Button.ClickEvent, func, ?subPatchOptions = subPatchOptions)

        (* omitting the other existing bindings for clarity *)
```

Please note that in the case of events, there is an optional value `subPatchOptions` that is provided for performance reasons

```fsharp
type [<Struct>] SubPatchOptions =
    /// Always updates the subscription. This should be used if you can't explicitly express your outer dependencies.
    | Always
    /// Never updates the subscription. This should be used most of the time. Use this if you don't depend on outer dependencies.
    | Never
    /// Update if 't changed. This is useful if you're using some state ('t) and need to update the subscription if that state changed.
    | OnChangeOf of obj
```

this property will indicate to Avalonia.FuncUI when to update a subscription.

You can also provide overloaded methods to improve the API surface of a control for example in [Textblock.fs](https://github.com/AvaloniaCommunity/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI.DSL/TextBlock.fs) we provide two `background` functions, one takes an IBrush and the other one takes a string.

```fsharp

[<AutoOpen>]
module TextBlock =
    open Avalonia
    open Avalonia.Controls
    open Avalonia.Media
    open Avalonia.Media.Immutable
    open Avalonia.FuncUI.Builder
    open Avalonia.FuncUI.Types

    let create (attrs: IAttr<TextBlock> list): IView<TextBlock> =
        ViewBuilder.Create<TextBlock>(attrs)

    type TextBlock with
        (* omitting other bindings for clarity *)

        static member background<'t when 't :> TextBlock>(value: IBrush) : IAttr<'t> =
            AttrBuilder<'t>.CreateProperty<IBrush>(TextBlock.BackgroundProperty, value, ValueNone)

        static member background<'t when 't :> TextBlock>(color: string) : IAttr<'t> =
            color |> Color.Parse |> ImmutableSolidColorBrush |> TextBlock.background

        (* omitting other bindings for clarity *)
```

If you wanted you could also add a `Color` overload to ease developer's time if it were the case

```fsharp
static member background<'t when 't :> TextBlock>(color: Color) : IAttr<'t> =
    color |> ImmutableSolidColorBrush |> TextBlock.background
```


# Components


# Component basics

FuncUI offers a Component inspired by ReactJS. Components allow you to organize views into reusable pieces.

There are two ways of creating a component.

## Component (fun ctx -> ...)

Creating a component using the regular constructor of the `Component` class. `Component` inherits from `Border` and therefore can be used like any other Avalonia control.

```fsharp
// create a Component that can be directly used in a Avalonia app
let component: Component = Component (fun ctx -> 
    TextBlock.create [
        TextBlock.text "Hello World!"
    ]
)

// use component as main view of an app
type MainWindow() as this =
    inherit HostWindow()
    do
        this.Content <- component

// embedd component in avalonia app
let control: ContentControl = ..
control.Content <- component
// Creating a component using the View DSL.
// The resulting IView can be used inside other components and with the View DSL.

```

## Component.create ("key", fun ctx -> ...)

Declaratively describes a component. Can be embedded in other views as this returns an `IView`

```fsharp
let greetingView (): IView = 
    Component.create ("greetingView", fun ctx -> 
        TextBlock.create [
            TextBlock.text "Hello World!"
        ]
    )

let view (): IView = 
    Component.create ("mainView", fun ctx -> 
        DockPanel.create [
            DockPanel.children [
                // use other component
                greetingView ()
            ]
        ]
    )
```


# Component lifetime

Components internally use a Virtual DOM to efficiently re-render themselves. As components can be nested it is important to understand how the Virtual DOM identifies a component.

## Component Identity - Location

If the location of a component (for example in a list of children) changes it is considered a new component.

In the example below we conditionally hide a button. If the button is hidden the location of the random color component below changes. Because the random color component is not considered the same, it is newly created. Therefor the color changes.

<div align="center"><img src="/files/0xMhujlVk7fidjJQEC6Q" alt=""></div>

```fsharp
type Views () =

    static let random = Random()
    
    static let randomColor () =
        String.Format("#{0:X6}", random.Next(0x1000000))
    
    static member randomColorView () =
        Component.create ("randomColorView", fun ctx ->
            let color = ctx.useState (randomColor())
            
            TextBlock.create [
                TextBlock.background color.Current
                TextBlock.text $"Color {color.Current}"
            ]
        )
        
    static member mainView () =
        Component (fun ctx ->
            let isHidden = ctx.useState false

            DockPanel.create [
                DockPanel.lastChildFill true
                DockPanel.children [
                    
                    if not isHidden.Current then
                        Button.create [
                            Button.content "hide button"
                            Button.onClick (fun _ -> isHidden.Set true)
                        ]
                    
                    Views.randomColorView ()
                ]
            ]
        )
```

Instead of removing the `Button` from the Virtual DOM we can also just set `isVisible` accordingly. This does not change the location of the `randomColorView` and will keep its identity.

```fsharp
..    

    static member mainView () =
        Component (fun ctx ->
            let isHidden = ctx.useState false

            DockPanel.create [
                DockPanel.lastChildFill true
                DockPanel.children [
                    
                    Button.create [
                        Button.content "hide button"
                        Button.onClick (fun _ -> isHidden.Set true)
                        Button.isVisible (not isHidden.Current)
                    ]
                    
                    Views.randomColorView ()
                ]
            ]
        )
```

![](/files/85wsBRKsFDZ5BQVY2VBx)

## Component Identity - Key

A Components identity can be explicitly changed by changing its key. This is useful when the location is stable, but you still want to get a new component in some cases.

```fsharp
type Views () =
    static member editorView 
      ( person: Person, 
        onSave: Person -> unit, 
        onDelete: unit -> unit ) =
        
        Component.create ($"edit-person-{person.Id}", fun ctx ->
            let person = ctx.useState person
            
            StackPanel.create [
                StackPanel.orientation Orientation.Vertical
                StackPanel.spacing 5
                StackPanel.children [
                    TextBox.create [
                        TextBox.watermark "First Name"
                        TextBox.text person.Current.FirstName
                        TextBox.onTextChanged (fun value ->
                             person.Set { person.Current with FirstName = value }
                        )
                    ]
                    
                    TextBox.create [
                        TextBox.watermark "Last Name"
                        TextBox.text person.Current.LastName
                        TextBox.onTextChanged (fun value ->
                             person.Set { person.Current with LastName = value }
                        )
                    ]
                    
                    StackPanel.create [
                        StackPanel.orientation Orientation.Horizontal
                        StackPanel.spacing 5
                        StackPanel.children [
                            Button.create [
                                Button.content "save"
                                Button.onClick (fun _ -> onSave person.Current)
                            ]
                            
                            Button.create [
                                Button.content "delete"
                                Button.onClick (fun _ -> onDelete ())
                            ]                            
                        ]
                    ]
                ]
            ]
        )
         
    static member mainView () =
        Component (fun ctx ->
            let people = ctx.usePassed State.people
            let selectedId = ctx.useState (None: Guid option)
            let selectedPerson =
                people
                |> State.tryFindByKey (fun person -> Some person.Id) selectedId
            
            DockPanel.create [
                DockPanel.lastChildFill true
                DockPanel.children [
                    
                    ListBox.create [
                        ListBox.dataItems people.Current
                        ListBox.itemTemplate (
                            DataTemplateView<Person>.create(fun person -> 
                                TextBlock.create [
                                    TextBlock.text 
                                        $"{person.FirstName} {person.LastName}"
                                ]
                            )
                        )
                        ListBox.onSelectedItemChanged (fun item ->
                            match item with
                            | null -> selectedId.Set (None: Guid option)
                            | item -> selectedId.Set (Some (item :?> Person).Id) 
                        )
                    ]
                    
                    ContentControl.create [
                        ContentControl.dock Dock.Right
                        ContentControl.padding 5
                        ContentControl.content (
                            match selectedPerson.Current with
                            | Some person ->
                                Views.editorView (
                                    person = person,
                                    onSave = (Some >> selectedPerson.Set),
                                    onDelete = (fun () -> selectedPerson.Set None)
                                ) :> IView
                            | None ->
                                TextBlock.create [
                                    TextBlock.padding (Thickness 5)
                                    TextBlock.text "No person selected"
                                ] :> IView
                        )
                    ]
                ]
            ]
        )
```

![](/files/uCO0Yey7XzfSuZm059wj)

If the key of \`personEditorView\` would not change (see example below) the component would never get re-created.

```fsharp
// BUG - component is never re-created
Component.create ("edit-person", fun ctx -> ..)
// WORKS - component is re-created when person changes
Component.create ($"edit-person-{person.Id}", fun ctx -> ..)
```

This is how it looks like if the component key does not change.

![](/files/7xnJnurFlbN8NCMtpdgK)


# Hooks

### useState

This is the most basic hook which allows you to create an instance of a value which can be both read and updated in your component's code, the state is kept between renders and any updates to it will cause it to re-render by default.

```fsharp
Component(fun ctx ->
    let state = ctx.useState 0
    
    // state var that does not rerender on change
    let state = ctx.useState (0, renderOnChange = false)
    
    // Component's UI
)
```

### useEffect

Sometimes you need to subscribe to an observable, to an `IWritable<'T>`, create a disposable value, or make some logging. For these and other scenarios you can use the `useEffect` hook.

This hook requires a `handler` which is a function that can return `unit` or `IDisposable` depending on your needs. For cases where you need to handle subscriptions the second will be better.

This hook also asks for a `triggers` list, these help Avalonia.FuncUI to decide when to run the handler function. The possible trigger values are defined as follows:

```fsharp
[<RequireQualifiedAccess>]
type EffectTrigger =
    /// triggers the effect to run every time after the passed dependency has changed.
    | AfterChange of state: IAnyReadable
    /// triggers the effect to run once after the component initially rendered.
    | AfterInit
    /// triggers the effect to run every time after the component is rendered.
    | AfterRender
```

For example if we had to fetch some resources from a server after the component is initialized we would do something like the following:

```fsharp
Component("use-effect-component", fun ctx ->
    let names = ctx.useState []
    let count = ctx.useState 0
    ctx.useEffect (
        handler = (fun _ ->
            // Common use cases here are HTTP Requests, Event and Observable Subscriptions
            // or any other code that could be considered a side effect
            async {
                let! nameList = httpLib.get "https://my-resources.com"
                // update the names value
                names.Set nameList
            }
            |> Async.Start
        ),
        triggers = [ EffectTrigger.AfterInit ]
    )
    // DSL code
)
```

We can also re-execute these handlers if we make them dependent on any readable values, for example let us try to compute the sum of the ages of a user list whenever the user list changes.

```fsharp
Component("use-effect-component", fun ctx ->
    let users = ctx.useState []
    let ageSum = ctx.useState 0
    ctx.useEffect (
        handler = (fun _ ->
            // Common use cases here are HTTP Requests, Event and Observable Subscriptions
            // or any other code that could be considered a side effect
            async {
                let! nameList = httpLib.get "https://my-resources.com"
                // update the names value
                names.Set nameList
            }
            |> Async.Start
        ),
        triggers = [ EffectTrigger.AfterInit ]
    )
    ctx.useEffect(
        handler = (fun _ ->
            // get sum of the ages of the users list
            users
            |> List.sumBy (fun user -> user.age)
            |> ageSum.Set
        ),
        // whenever the users list changes, trigger this effect
        triggers = [ EffectTrigger.AfterChange users ]
    )
)
```

### IReadable<'T>

```fsharp
type IReadable<'value> =
    inherit IAnyReadable
    abstract member Current: 'value with get
    abstract member Subscribe : ('value -> unit) -> IDisposable
```

As is in the source comments:

> Readable state value that can be subscribed to.

Readables are values to which you can subscribe to get updates, these are commonly used values.

An example would be the following:

```fsharp
Component(fun ctx ->
    let state = ctx.useState 0

    Button.create [
        Button.content $"Count: {state.Current}"
    ]
)
```

At this point this component will be pretty much static, it won't ever be re-rendered because there are no changes to its state.

### IWritable<'T>

```fsharp
type IWritable<'value> =
    inherit IReadable<'value>
    abstract member Set : 'value -> unit
```

As is in the source comments:

> Readable and writable state value that can be subscribed to.

If we take the previous example and add mutations, it would look like the following:

```fsharp
Component(fun ctx ->
    let state = ctx.useState 0

    Button.create [
        Button.content $"Count: {state.Current}"
        Button.onClick (fun _ -> state.Current + 1 |> state.Set)
    ]
)
```

#### Passed Values

Sometimes when you already have an `IWritable<'T>` value, you would like to use it on sibling components so they can show the same data in different formats, or just to communicate changes between different component trees without having to drill the values into the component's tree.

For that we can use Passed Values.

```fsharp

let ComponentA id (value: IWritable<string>) =
    Component(id, fun ctx ->
        // Right here we can use ctx.usePassed to ensure we can both read/update a value
        let value = ctx.usePassed value
        StackPanel.create [
            StackPanel.children [
                TextBlock.create [
                    TextBlock.text $"This component can read and update this value: \"{value.Current}\""
                ]
                Button.create [
                    Button.content "Add 3"
                    Button.onClick (fun _ -> $"{value.Current}3" |> value.Set )
                ]
            ]
        ]
    )

let ComponentB id (value: IReadable<string>) =
    Component(id, fun ctx ->
        // Right here we can use ctx.usePassedRead to ensure we can only read a value
        let value = ctx.usePassedRead value
        StackPanel.create [
            StackPanel.children [
                TextBlock.create [
                    TextBlock.text $"This component can only read this value: \"{value.Current}\""
                ]
            ]
        ]
    )

let View =
    Component(fun ctx ->
        let value = ctx.useState "This is my value"
        StackPanel.create [
            StackPanel.spacing 12.
            StackPanel.children [
                // here we can use our components with the existing value
                // in other implementations these could also be called
                // "Stores"
                ComponentA "component-a" value
                ComponentB "component-b" value
                Button.create [
                    Button.content "I can add 4 from outside"
                    // since state is both readable and writable we can also
                    // modify the values from outside the child components
                    // as usual
                    Button.onClick (fun _ -> $"{value.Current}4" |> value.Set )
                ]
            ]
        ]
    )
```


# Common Questions

## How do I obtain the reference of a Control?

There are 2 recommended ways of obtaining the reference of an underlying control. \\

### 1. Execute code on control creation

Use the Control.init attribute to run code on control creation.

```fsharp
ListBox.create [
    ListBox.init (fun listBox ->
        listBox.Items <- [ 1 .. 3 ]
    )
]
```

### 2. Obtain a view reference via an outlet

Calls the `listBox.Set` function when the control is created.

```fsharp
Component(fun ctx ->
    let listBox = ctx.useState<ListBox>(null)
    
    ctx.useEffect (
        handler = (fun _ ->
            listBox.Current.Items <- [ 1 .. 3 ]    
        ),
        triggers = [ EffectTrigger.AfterInit ]
    )
    
    View.createWithOutlet listBox.Set ListBox.create [ ]
)
```

## How do I obtain the reference of a Component?

The Component reference can be accessed via `ctx.control`.

```fsharp
Component(fun ctx ->
    ctx.useEffect (
        handler = (fun _ ->
            ctx.control.Tag <- 0
        ),
        triggers = [ EffectTrigger.AfterInit ]
    )
    Button.create []
)
```

## How to set attributes on Component level?

```fsharp
Component(fun ctx ->
    ctx.attrs [
        Component.background "transparent"
        Component.borderThickness 1
    ]
    Button.create []
)
```

## How do I restrict what a user can input in a TextBox / AutoCompleteBox / InputElement ?

This is possible by intercepting the [TextInputEvent](https://reference.avaloniaui.net/api/Avalonia.Input/InputElement/FEA4DB21) and modifying its event args. It's important to attach the handler to the tunnelled event. More details about event routing can be found [here](https://docs.avaloniaui.net/docs/input/routed-events#routing-strategies).\
\
In the example below whatever a user types in a TextBox will end up as uppercase text.

```fsharp
TextBox.create [
    TextBox.init (fun control ->
        control.AddHandler(
            TextBox.TextInputEvent,
            (fun sender args ->
                args.Text <- args.Text.ToUpper()
            ),
            RoutingStrategies.Tunnel
        )
    )
]
```

Here another example that prevents users from entering anything but numbers.

```fsharp
TextBox.create [
    TextBox.init (fun control ->
        control.AddHandler(
            TextBox.TextInputEvent,
            (fun sender args -> args.Text <- String.filter Char.IsNumber args.Text),
            RoutingStrategies.Tunnel
        )
    )
] 
```

## How to render a Control to an Image?

```fsharp
let renderToFile (target : Control, path : string) = 
    let pixelSize = PixelSize(int target.Bounds.Width, int target.Bounds.Height) 
    let size = Size(target.Bounds.Width, target.Bounds.Height) 
    use bitmap = new RenderTargetBitmap(pixelSize, new Vector(96.0, 96.0)) 
    target.Measure(size) 
    target.Arrange(Rect(size)) 
    bitmap.Render(target) 
    bitmap.Save(path) 
```

## Managing Focus

<figure><img src="/files/PpMO6HaGRriM5aPR4Fen" alt="" width="345"><figcaption></figcaption></figure>

```fsharp
Component.create ("view", fun ctx ->
    let textBoxA = ctx.useState<TextBox>(null, renderOnChange = false)
    let textBoxB = ctx.useState<TextBox>(null, renderOnChange = false)
    let textBoxAFocus = ctx.useState(false, renderOnChange = true)
    let textBoxBFocus = ctx.useState(false, renderOnChange = true)
    StackPanel.create [
        StackPanel.margin 10
        StackPanel.spacing 10
        StackPanel.children [
            TextBox.create [
                TextBox.init textBoxA.Set
                TextBox.onGotFocus (fun _ -> textBoxAFocus.Set true)
                TextBox.onLostFocus (fun _ -> textBoxAFocus.Set false)
            ]
            TextBox.create [
                TextBox.init textBoxB.Set
                TextBox.onGotFocus (fun _ -> textBoxBFocus.Set true)
                TextBox.onLostFocus (fun _ -> textBoxBFocus.Set false)
            ]
            StackPanel.create [
                StackPanel.orientation Orientation.Horizontal
                StackPanel.margin 10
                StackPanel.spacing 10
                StackPanel.children [
                    Button.create [
                        Button.content "Focus A"
                        Button.background (if textBoxAFocus.Current then Brushes.Green else Brushes.Red)
                        Button.onClick (fun _ ->
                            let _ = textBoxA.Current.Focus()
                            ()
                        )
                    ]
                    Button.create [
                        Button.content "Focus B"
                        Button.background (if textBoxBFocus.Current then Brushes.Green else Brushes.Red)
                        Button.onClick (fun _ ->
                            let _ = textBoxB.Current.Focus()
                            ()
                        )
                    ]
                ]
            ]
        ]
    ]
)
```


# Controls


# Button

> *Note*: You can check the Avalonia docs for the [Button](https://docs.avaloniaui.net/docs/controls/button) and [Button API](http://reference.avaloniaui.net/api/Avalonia.Controls/Button/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [Button.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Buttons/Button.fs)

Buttons are basic controls for any application you may build, buttons are often used to trigger an action.

### Usage

> You can check the general usage of Avalonia.FuncUI's views and attributes in the following link Views and Attributes

**Create a Button**

```fsharp
Button.create []
```

**Register Click**

```fsharp
Button.create [
  Button.onClick(fun _ -> dispatch MyMsg)
]
```

**Set Click Mode**

```fsharp
Button.create [
  Button.clickMode ClickMode.Press
]
// or
Button.create [
  Button.clickMode ClickMode.Release
]
```

> for more information check the [Click Mode](http://reference.avaloniaui.net/api/Avalonia.Controls/ClickMode/) docs

**Set Content**

```fsharp
Button.create [ Button.content "My Button" ]
```

Buttons can have arbitrary content, for example it can be a string as the example above. It also can be another entire control like a StackPanel

```fsharp
let playIcon =
  Canvas.create [ ... ]
let textbox =
  TextBox.create [ ... ]

let iconAndTextBlock =
  StackPanel.create [
    StackPanel.orientation Horizontal
    StackPanel.spacing 8.0
    StackPanel.children [ playIcon; textbox ]
  ]
Button.create [
  Button.content iconAndTextBlock
]
```


# Border

> *Note*: You can check the Avalonia docs for the [Border](https://docs.avaloniaui.net/docs/controls/border) and [Border Api](http://reference.avaloniaui.net/api/Avalonia.Controls/Border/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [Border.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Border.fs)

The Border control allows you to decorate child controls

### Usage

**Set Background** Avalonia.FuncUI has some overloads for you to take advantage of

```fsharp
Border.create [
  Border.background "black"
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
Border.create [
  Border.background "#000000"
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

> You can pass any [IBrush](http://reference.avaloniaui.net/api/Avalonia.Media/IBrush/) compatible instance to the background for more control

**Set Border Brush** Avalonia.FuncUI has some overloads for you to take advantage of

```fsharp
Border.create [
  Border.borderBrush "red"
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

```fsharp
Border.create [
  Border.borderBrush "#FF0000"
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

> You can pass any [IBrush](http://reference.avaloniaui.net/api/Avalonia.Media/IBrush/) compatible instance to the background for more control

**Thickness**

```fsharp
Border.create [
  Border.borderThickness 2.0
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

**Horizontal and Vertical Thickness**

```fsharp
Border.create [
  Border.borderThickness (2.0, 5.0)
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

**Left, Top, Right, Bottom Thickness**

```fsharp
Border.create [
  Border.borderThickness (1.0, 2.0, 3.0, 4.0)
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

> You can also pass a [Thickness](http://reference.avaloniaui.net/api/Avalonia/Thickness/) struct to the borderThickness property

**Corner Radius**

```fsharp
Border.create [
  Border.cornerRadius 3.0
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

**Horizontal and Vertical Corner Radius**

```fsharp
Border.create [
  Border.cornerRadius (2.0, 5.0)
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

**Left, Top, Right, Bottom Corner Radius**

```fsharp
Border.create [
  Border.cornerRadius (1.0, 2.0, 3.0, 4.0)
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```

> You can also pass a [Corner Radius](http://reference.avaloniaui.net/api/Avalonia/CornerRadius/) struct to the cornerRadius property

```fsharp
Border.create [
  Border.cornerRadius (CornerRadius 3.0)
  Border.child (StackPanel.create [ /* ... definition ... */ ])
]
```


# Calendar

> *Note*: You can check the Avalonia docs for the [Calendar](https://docs.avaloniaui.net/docs/controls/calendar) and [Calendar API](http://reference.avaloniaui.net/api/Avalonia.Controls/Calendar/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [Calendar.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Calendar/Calendar.fs)

The Calendar control is a standard Calendar control for users to select date(s) or date ranges.

### Usage

**Set a Date**

If no calendar date is set, it will default to today's date.

```fsharp
Calendar.create [
  Calendar.selectedDate DateTime.Today
]
```

**Select Multiple Dates**

For more information about selection modes you can see the [SelectionModes API](http://reference.avaloniaui.net/api/Avalonia.Controls/SelectionMode/) but more verbosely you can look at the [ListBox Selection Modes](https://docs.avaloniaui.net/docs/controls/listbox#selectionmode) for a better description of what they do.

```fsharp
Calendar.create [
  Calendar.selectionMode SelectionMode.Multiple
]
```

**Select Calendar Month First**

You can change the [CalendarMode](http://reference.avaloniaui.net/api/Avalonia.Controls/CalendarMode/) so that you can select the year first with `CalendarMode.Decade`, the month first with `CalendarMode.Year`, or have the standard (default) format with `CalendarMode.Month`.jok

```fsharp
Calendar.create [
  Calendar.displayMode CalendarMode.Decade
]
```

**Display Only the Upcoming Week**

```fsharp
Calendar.create [
  Calendar.displayDateStart DateTime.Today
  Calendar.displayDateEnd (DateTime.Today + TimeSpan(7, 0, 0, 0, 0)) // TimeSpan constructor for 7 days
]
```


# CalendarDatePicker

> *Note*: You can check the Avalonia docs for the [CalendarDatePicker API](http://reference.avaloniaui.net/api/Avalonia.Controls/CalendarDatePicker/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [CalendarDatePicker.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Calendar/CalendarDatePicker.fs)

The CalendarDatePicker control is a single date picker that displays a calendar, it is also possible to enter a date via the TextBox the control has

### Usage

**Set Date**

```fsharp
CalendarDatePicker.create [
  CalendarDatePicker.selectedDate DateTime.Today
]
```

**Set DateFormat**

```fsharp
CalendarDatePicker.create [
  CalendarDatePicker.selectedDateFormat DatePickerFormat.Long
]

CalendarDatePicker.create [
  CalendarDatePicker.selectedDateFormat DatePickerFormat.Short
]

CalendarDatePicker.create [
  CalendarDatePicker.selectedDateFormat DatePickerFormat.Custom
  // It can be any valid DateFormat string
  CalendarDatePicker.customDateFormatString "MMMM dd, yyyy"
]
```

> For more information about the CalendarDatePickerFormat check [DatePickerFormat](http://reference.avaloniaui.net/api/Avalonia.Controls/DatePickerFormat/)

> You can check [Custom date and time format strings](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings/) Microsoft docs for more information about the format string

**Set Start Display Date**

Sets the first date available to display

```fsharp
let startFromYesterday =
   DateTime.Today.Subtract(TimeSpan.FromDays(1.0))
CalendarDatePicker.create [
  CalendarDatePicker.displayDateStart startFromYesterday
]
```

**Set End Display Date**

Sets the last date available to display

```fsharp
let showUpToTomorrow =
  DateTime.Today.Add(TimeSpan.FromDays(1.0))
CalendarDatePicker.create [
  CalendarDatePicker.displayDateStart showUpToTomorrow
]
```

**Set Watermark**

Sets the watermark (placeholder) for the TextBox that is included in this control

```fsharp
CalendarDatePicker.create [
  CalendarDatePicker.watermark "Select a date"
]
```


# CheckBox

> *Note*: You can check the Avalonia docs for the [CheckBox](https://docs.avaloniaui.net/docs/controls/checkbox) and [CheckBox API](http://reference.avaloniaui.net/api/Avalonia.Controls/CheckBox/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [CheckBox.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Buttons/CheckBox.fs)

The checkbox is a control that allows a user to represent boolean values or the absense of a value

### Usage

**Set Label**

```fsharp
CheckBox.create [
  CheckBox.content "I Accept the terms and conditions."
]
```

**Set Is Checked**

```fsharp
CheckBox.create [
  // can be either true or false
  CheckBox.isChecked state.booleanValue
]
```

**Set Indeterminate**

```fsharp
CheckBox.create [
  // can be either true or false
  CheckBox.isThreeState state.indeterminate
  // this value is required to be either a nullable boolean
  // or a boolean option
  CheckBox.isChecked None
]
```

> To be able to set the indeterminate state, the `isThreeState` value must be true and the `isChecked` value must be None or Nullable boolean set to null

**Set Dynamic State Checkbox**

You can mix and match the three states of a checkbox. In this example if the count value is greater than 0 the box will be checked, if the value is 0 then it will be indeterminate, lastly if the value is less than 0 it will be unchecked

```fsharp
let isChecked =
  if state.count = 0 then
    None
  else if state.count > 0 then
    Some true
  else
    Some false

CheckBox.create [
  CheckBox.content "Dynamic CheckBox"
  // this is not required
  CheckBox.isEnabled false
  CheckBox.isThreeState (state.count = 0)
  CheckBox.isChecked isChecked
]
```


# DatePicker

> *Note*: You can check the Avalonia docs for the [DatePicker](https://docs.avaloniaui.net/docs/controls/datepicker) and [DatePicker API](http://reference.avaloniaui.net/api/Avalonia.Controls/DatePicker/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [DatePicker.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/DatePicker.fs)

The DatePicker control is a single date picker that displays a calendar, it is also possible to enter a date via the TextBox the control has

### Usage

**Set Label**

```fsharp
DatePicker.create [
  DatePicker.header "Title"
]
```

**Set Date**

```fsharp
DatePicker.create [
  DatePicker.selectedDate DateTime.Today
]
```

**Set DateFormat**

```fsharp
DatePicker.create [
  DatePicker.yearFormat "yyyy"
  DatePicker.monthFormat "MMMM"
  DatePicker.dayFormat "dd"
]
```

> You can check [Custom date and time format strings](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings/) Microsoft docs for more information about the format strings.

**Limit Year Range**

> You can check [DateTimeOffset](https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset?view=net-6.0) Microsoft docs for more information about setting time offsets.

```fsharp
DatePicker.create [
  DatePicker.maxYear (DateTimeOffset(DateTime.Now))
]
```

**Show Only Month and Year**

You can control the visibility of the day, month, and year with similarly named functions.

```fsharp
DatePicker.create [
  DatePicker.dayVisible false
]
```

**Register Selected Date**

```fsharp
DatePicker.create [
  DatePicker.onSelectedDateChanged (fun dateOffset -> OnChangeDateOffset dateOffset |> dispatch)
]
```


# DockPanel

> *Note*: You can check the Avalonia docs for the [DockPanel](https://docs.avaloniaui.net/docs/controls/dockpanel) and [DockPanel API](http://reference.avaloniaui.net/api/Avalonia.Controls/DockPanel/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [DockPanel.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Panels/DockPanel.fs)

The DockPanel is a layout construct that allows docking its children to the different sides of it.

### Usage

#### Basic Usage

```fsharp
DockPanel.create [
  DockPanel.children [
    // Some child control
    [..].dock Dock.Top // you can use Left, Right, Top and Bottom
  ]
]
```

You can use multiple dockings inside of one panel. It will dock in order of the children list (you can see that in the example).

**Example**

```fsharp
DockPanel.create [
  DockPanel.children [
    Border.create [
      Border.background "blue"
      Border.dock Dock.Left
      Border.padding 20.
    ]
    Border.create [
      Border.background "green"
      Border.dock Dock.Bottom
      Border.padding 20.
    ]
    Border.create [
      Border.background "red"
      Border.dock Dock.Right
      Border.padding 20.
    ]
    Border.create [
      Border.background "orange"
      Border.dock Dock.Top
      Border.padding 20.
    ]
    Border.create [
      Border.background "purple"
      Border.dock Dock.Left
      Border.padding 20.
    ]
    Border.create [
      Border.background "yellow"
    ]
  ]
]
```


# Expander

> *Note*: You can check the Avalonia docs for the [Expander](https://docs.avaloniaui.net/docs/controls/expander) and [Expander API](http://reference.avaloniaui.net/api/Avalonia.Controls/Expander/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [Expander.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Expander.fs)

The Expander (known as accordion as well) is a control that allows a user to show or hide content to make more room for relevant information or to show detailed information about the current view

### Usage

**Set Label**

```fsharp
Expander.create [
    Expander.header "Check Logs"
    // the Logs property may be an extremely long text that's why we use an expander
    // hide the logs unless you want to see them
    Expander.content (TextBlock.create [ TextBlock.text state.Logs ])
]
```

**Change Expand Direction** you can set in which direction the content should flow

```fsharp
Expander.create [
    Expander.groupName "newsletter"
    Expander.content expanderContent
    // ExpandDirection.Up
    // ExpandDirection.Down
    // ExpandDirection.Left
    // ExpandDirection.Right
    Expander.expandDirection ExpandDirection.Up
]
```

**Use Different Transitions**

```fsharp
Expander.create [
    Expander.groupName "newsletter"
    Expander.content expanderContent
    // supply an IPageTransition
    // Expander.contentTransition (PageSlide(TimeSpan.FromSeconds(3.5), PageSlide.SlideAxis.Horizontal) :> IPageTransition)
    Expander.contentTransition (CrossFade(TimeSpan.FromSeconds(2.5)) :> IPageTransition)
]
```

**Use Multiple Expanders** you can use multiple expanders and open them programatically via their `isExpanded` property

```fsharp
Expander.create [
    Expander.header "Profile"
    Expander.isExpanded (state.CurrentSection = Sections.Profile)
    Expander.content (TextBlock.create [ TextBlock.text state.Logs ])
    Expander.onIsExpandedChanged(
        (fun isExpanded -> 
            if isExpanded then
            dispatch (SetCurrentSection (Sections.Profile))
        ), OnChangeOf(state.CurrentSection))
]
Expander.create [
    Expander.header "Preferences"
    Expander.isExpanded (state.CurrentSection = Sections.Preferences)
    Expander.content (TextBlock.create [ TextBlock.text state.Logs ])
    Expander.onIsExpandedChanged(
        (fun isExpanded -> 
            if isExpanded then
            dispatch (SetCurrentSection (Sections.Preferences))
        ), OnChangeOf(state.CurrentSection))
]
Expander.create [
    Expander.header "Misc. Information"
    Expander.isExpanded (state.CurrentSection = Sections.Preferences)
    Expander.content (TextBlock.create [ TextBlock.text state.Logs ])
    Expander.onIsExpandedChanged(
        (fun isExpanded -> 
            if isExpanded then
            dispatch (SetCurrentSection (Sections.Preferences))
        ), OnChangeOf(state.CurrentSection))
]
```


# ListBox

> *Note*: You can check the Avalonia docs for the [ListBox](https://docs.avaloniaui.net/docs/controls/listbox) and [ListBox API](http://reference.avaloniaui.net/api/Avalonia.Controls/ListBox/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [ListBox.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/ListBox.fs)

The list box is a multi-line control box for allowing a user to choose value.

### Usage

**Create a list box**

```fsharp
ListBox.create [
    ListBox.dataItems [ "Linux"; "Mac"; "Windows" ]
]
```

**Multiple Item Selection Mode**

You can choose different [ListBox Selection Modes](https://docs.avaloniaui.net/docs/controls/listbox#selectionmode). The default is to only select a single element.

```fsharp
ListBox.create [
    ListBox.dataItems [ "Linux"; "Mac"; "Windows" ]
    ListBox.selectionMode Selection.Multiple
]
```

**Using Discriminated Unions**

```fsharp
type OperatingSystem =
    | Linux
    | Mac
    | Windows

ListBox.create [
    ListBox.dataItems [ Linux; Mac; Windows ]
]
```

**Controlling Selected Item**

To override the controls default behavior you need to add both `selectedItem` and `onSelectedItemChanged`

```fsharp
ListBox.create [
    ListBox.dataItems [ "Linux"; "Mac"; "Windows" ]
    ListBox.selectedItem state.os
    ListBox.onSelectedItemChanged (fun os -> dispatch ChangeOs)
]
```

**Controlling Selected Item by Index**

To override the controls default behavior you need to add both `selectedItem` and `onSelectedItemChanged`

```fsharp
ListBox.create [
    ListBox.dataItems [ "Linux"; "Mac"; "Windows" ]
    ListBox.selectedIndex state.osIndex
    ListBox.onSelectedIndexChanged (fun os -> dispatch ChangeOsIndex)
]
```


# Menu

> *Note*: You can check the Avalonia docs for the [Menu API](http://reference.avaloniaui.net/api/Avalonia.Controls/Menu/) and [Menu](http://docs.avaloniaui.net/docs/controls/menu) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [Menu.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Menu.fs)

The menu control allows you to add a list of buttons in a horizontal manner which supports sub-items, it's usually put at the top of the application inside a DockPanel, but it can be placed anywhere in the application.

### Usage

**Top-Level Menu Items**

To create top-level navigation menus you just need to provide a list of `MenuItem` controls and use the `.viewItems` property on the [Menu](http://docs.avaloniaui.net/docs/controls/menu) control

```fsharp
let menuItems = [
    MenuItem.Create [
        MenuItem.header "File"
    ]
    MenuItem.Create [
        MenuItem.header "Edit"
    ]
]

Menu.create [
  Menu.viewItems menuItems
]
```

**Set Sub-Menus**

Each MenuItem can contain MenuItems themselves if you need a sub-menu you just need to provide the appropriate children

```fsharp
let fileItems = [
  MenuItem.Create [
    MenuItem.header "Open File"
  ]
  MenuItem.Create [
    MenuItem.header "Open Folder"
  ]
]

let menuItems = [
  MenuItem.Create [
   MenuItem.header "Files"
   MenuItem.viewItems fleItems
  ]
  MenuItem.Create [
    MenuItem.header "Preferences"
  ]
]

Menu.create [
  Menu.viewItems menuItems
]
```

**Set Icons**

To add Icons to the menu item you just need to provide an [Image](http://avaloniaui.net/docs/controls/image), you can check this [sample](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Examples/Elmish%20Examples/Examples.Elmish.MusicPlayer/Shell.fs#L160) which uses an extension method defined in [this file](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Examples/Elmish%20Examples/Examples.Elmish.MusicPlayer/Extensions.fs#L22)

```fsharp
let icon = (* obtain an Image instance *)
let menuItems = [
  MenuItem.Create [
    MenuItem.header "Files"
    MenuItem.icon icon
  ]
  MenuItem.Create [
    MenuItem.header "Preferences"
  ]
]

Menu.create [
  Menu.viewItems menuItems
]
```

**Dispatch Actions From Menu Items**

```fsharp
let menuItems = [
  MenuItem.Create [
    MenuItem.header "About"
    MenuItem.onClick(fun _ -> dispatch GoToAbout)
  ]
]

Menu.create [
  Menu.viewItems menuItems
]
```


# NativeMenu

> You can check the [NativeMenu](https://docs.avaloniaui.net/docs/controls/nativemenu) and [NativeMenu API](http://reference.avaloniaui.net/api/Avalonia.Controls/NativeMenu) Avalonia docs for more information

Native menus were introduced in Avalonia in version 0.9.0, you can check the [announcement](https://avaloniaui.net/blog/#osx-linux-native-menus) to see a brief explanation on how to use them in Avalonia Applications.

Currently for Avalonia.FuncUI there is not a DSL and the NativeMenu control is in a weird spot for Avalonia.FuncUI since this control works directly on the main Application/Window object so it's tough to pull a DSL on top of that. But! thankfully you can just use plain F# for the menu as noted [in this issue](https://github.com/AvaloniaCommunity/Avalonia.FuncUI/issues/113).

### Usage

Inside your `Program.fs` File find the `App` class and be sure to set the name of your Application

```fsharp
type MainWindow() as this = (*... code ... *)

type App() =
    inherit Application()

    override this.Initialize() =
        this.Styles.Load "avares://Avalonia.Themes.Default/DefaultTheme.xaml"
        this.Styles.Load "avares://Avalonia.Themes.Default/Accents/BaseDark.xaml"

        // 🚩name visible in native menu
        this.Name <- "Counter App"

    override this.OnFrameworkInitializationCompleted() =
        match this.ApplicationLifetime with
        | :? IClassicDesktopStyleApplicationLifetime as desktopLifetime ->
            desktopLifetime.MainWindow <- MainWindow()
        | _ -> ()
```

then just create a new NativeMenu

```fsharp
type MainWindow() as this =
    inherit HostWindow()
    do
        base.Title <- "Counter Example"
        base.Height <- 400.0
        base.Width <- 400.0

        // 🚩create menu and menu items
        let incrementItem = NativeMenuItem "Increment"
        let decrementItem = NativeMenuItem "Decrement"

        let editCounterItem = NativeMenuItem "Edit Counter"
        let editCounterMenu =  NativeMenu()
        editCounterItem.Menu <- editCounterMenu
        editCounterMenu.Add incrementItem
        editCounterMenu.Add decrementItem

        let nativeMenu = NativeMenu()
        nativeMenu.Add editCounterItem

        // 🚩set menu
        NativeMenu.SetMenu(this, nativeMenu)

        Elmish.Program.mkSimple (fun () -> Counter.init) Counter.update Counter.view
        |> Program.withHost this
        |> Program.withConsoleTrace
        |> Program.run
```

and that is enough to show your native menu. If you want to interact with the contents of your menu (the most likely scenario) you will need to add some subscriptions to hook up with your Elmish program

```fsharp
// 🚩hook menu actions in Elmish
let menuSub (_state: Counter.State) =
    let sub (dispatch: Counter.Msg -> unit) =
        incrementItem.Clicked.Add (fun _ -> dispatch Counter.Msg.Increment)
        decrementItem.Clicked.Add (fun _ -> dispatch Counter.Msg.Decrement)
        ()
    Cmd.ofSub sub

Elmish.Program.mkSimple (fun () -> Counter.init) Counter.update Counter.view
|> Program.withHost this
// 🚩 use menu subscription
|> Program.withSubscription menuSub

|> Program.withConsoleTrace
|> Program.run
```


# NumericUpDown

> *Note*: You can check the Avalonia docs for the [NumericUpDown](https://docs.avaloniaui.net/docs/controls/numericupdown) and [NumericUpDown API](http://reference.avaloniaui.net/api/Avalonia.Controls/NumericUpDown/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [NumericUpDown.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/NumericUpDown.fs)

The NumericUpDown is an editable numeric input field. The control has a up and down button spinner attached, used to increment and decrement the value in the input field. The value can also be incremented or decremented using the arrow keys or the mouse wheel when the control is selected.

### Usage

**Input with local currency**

Adding the `NumericUpDown.minimum` or `NumericUpDown.maximum` attributes will limit the input for both button increment/decrement changes and text input changes.

For more information about rendering the controls value you can check out the documentation for [Numeric String Formats](https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings).

```fsharp
NumericUpDown.create [
    NumericUpDown.minimum 0.
    NumericUpDown.maximum 10.
    NumericUpDown.formatString "C2"
    NumericUpDown.increment 0.25
]
```

**Simple numeric input**

If you want to disable the increment/decrement buttons you can add `NumericUpDown.allowSpin false`. If you then also want to remove visibility of the buttons you can add `NumericUpDown.showButtonSpinner false`.

```fsharp
NumericUpDown.create [
    NumericUpDown.minimum 0.
    NumericUpDown.minimum 100.
    NumericUpDown.showButtonSpinner false
    NumericUpDown.allowSpin false
]
```

**State controlled input**

```fsharp
NumericUpDown.create [
    NumericUpDown.minimum 0.
    NumericUpDown.formatString "C2"
    NumericUpDown.value state.price
    NumericUpDown.onValueChanged (fun newPrice -> ChangePrice price |> dispatch )
]
```


# ProgressBar

> *Note*: You can check the Avalonia docs for the [ProgressBar](https://docs.avaloniaui.net/docs/controls/progressbar) and [ProgressBar API](http://reference.avaloniaui.net/api/Avalonia.Controls/ProgressBar/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [ProgressBar.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/ProgressBar.fs)

The ProgressBar control allow for showing dynamic progress status.

### Usage

**Basic Progress Bar**

```fsharp
ProgressBar.create [
    ProgressBar.value 50.
    ProgressBar.maximum 100.
    // Minimum default value is set to 0
]
```

**Indeterminate Animated Progress Bar**

```fsharp
ProgressBar.create [
    ProgressBar.isIndeterminate true
]
```


# RadioButton

> *Note*: You can check the Avalonia docs for the [RadioButton](https://docs.avaloniaui.net/docs/controls/radiobutton) and [RadioButton API](http://reference.avaloniaui.net/api/Avalonia.Controls/RadioButton/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [RadioButton.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Buttons/RadioButton.fs)

The RadioButton is a control that allows a user to choose a single value between different options

### Usage

**Set Label**

```fsharp
RadioButton.create [
    RadioButton.content "Opt in to the newsletter"
]
RadioButton.create [
    RadioButton.content "Opt out to the newsletter"
]
```

**Set Is Checked**

```fsharp
RadioButton.create [
    RadioButton.content "Opt in to the newsletter"
    RadioButton.isChecked state.newsLetterOptIn
]
```

**Use A Group of RadioButtons**

```fsharp
RadioButton.create [
    RadioButton.groupName "newsletter"
    RadioButton.content "Opt in to the newsletter"
    RadioButton.isChecked state.newsLetterOptIn
    // remember to use OnChangeOf to give FuncUI hints about when to dispatch the messages
    RadioButton.onChecked ((fun _ -> dispatch OptIn), OnChangeOf(state.newsLetterOptIn))
]
RadioButton.create [
    RadioButton.groupName "newsletter"
    RadioButton.content "Opt out to the newsletter"
    RadioButton.isChecked (not state.newsLetterOptIn)
    // remember to use OnChangeOf to give FuncUI hints about when to dispatch the messages
    RadioButton.onChecked ((fun _ -> dispatch OptOut), OnChangeOf(state.newsLetterOptIn))
]
```


# RepeatButton

> *Note*: You can check the Avalonia docs for the [RepeatButton](https://docs.avaloniaui.net/docs/controls/repeatbutton) and [RepeatButton API](http://reference.avaloniaui.net/api/Avalonia.Controls/RepeatButton/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [RepeatButton.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/RepeatButton.fs)

A `RepeatButton` is a subclasses of \[Button] so they share all the same attributes as described on that documentation page. The biggest difference is that when a `RepeatButton` is held down, the button submits multiple `onClick` events.

**Creating a RepeatButton**

The `RepeatButton.delay` sets the amount of time in milliseconds before the extra `onClick` events start triggering. The `RepeatButton.interval` sets the amount of time in milliseconds between successive `onClick` events

```fsharp
RepeatButton.create [
    RepeatButton.delay 100 // ms
    RepeatButton.interval 250 // ms
    RepeatButton.onClick (fun _ -> dispatch RepeatButtonCicked)
]
```


# Slider

> *Note*: You can check the Avalonia docs for the [Slider](https://docs.avaloniaui.net/docs/controls/slider) and [Slider API](http://reference.avaloniaui.net/api/Avalonia.Controls/Slider/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [Slider.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Slider.fs)

The Slider control is a control that lets the user select from a range of values by moving a Thumb control along a track.

### Usage

**Percentage Slider**

```fsharp
Slider.create [
    Slider.minimum 0.
    Slider.maximum 0.
    Slider.value state.Percentage
    Slider.onValueChanged (fun newPercentage -> ChangePercentage newPercentage |> dispatch)

]
```


# StackPanel

> *Note*: You can check the Avalonia docs for the [StackPanel](https://docs.avaloniaui.net/docs/controls/stackpanel) and [StackPanel API](http://reference.avaloniaui.net/api/Avalonia.Controls/StackPanel/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [StackPanel.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Panels/StackPanel.fs)

The StackPanel is a layout construct that stacks its children in horizontal or vertical direction.

### Usage

#### Basic Usage

```fsharp
StackPanel.create [
    StackPanel.orientation Orientation.Horizontal // Orientation can be Horizontal or Vertical
    StackPanel.children [
        // This can be a list of different controls, which are stacked inside of the StackPanel
    ]
]
```

**Example**

```fsharp
StackPanel.create [
    StackPanel.orientation Orientation.Vertical
    StackPanel.children [
        Button.create [
            Button.content "Import"
            Button.padding (40., 14.)
        ]
        Button.create [
            Button.content "Analyse"
            Button.padding (40., 14.)
        ]
        Button.create [
            Button.content "Publish"
            Button.padding (40., 14.)
        ]
    ]
]
```

#### Spacing

```fsharp
StackPanel.create [
    StackPanel.orientation Orientation.Horizontal
    StackPanel.spacing 10. // Adds space between stacked items
    StackPanel.children [
        // List of stacked controls
    ]
]
```

**Example**

```fsharp
StackPanel.create [
    StackPanel.orientation Orientation.Vertical
    StackPanel.spacing 10.
    StackPanel.children [
        Button.create [
            Button.content "Import"
            Button.padding (40., 14.)
        ]
        Button.create [
            Button.content "Analyse"
            Button.padding (40., 14.)
        ]
        Button.create [
            Button.content "Publish"
            Button.padding (40., 14.)
        ]
    ]
]
```


# Tabs

> *Note*: You can check the Avalonia docs for the [TabControl](http://docs.avaloniaui.net/docs/controls/tabcontrol) and [TabControl API](http://reference.avaloniaui.net/api/Avalonia.Controls/TabControl/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [TabControl.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/TabControl.fs)

The [TabControl](http://docs.avaloniaui.net/docs/controls/tabcontrol) offers you a way to present content inside your application, each tab contains a different set of controls.

**Set Tabs**

```fsharp
let homePageContent = 
    DockPanel.create [ 
        DockPanel.children [
            TextBox.create [ TextBox.text "Home" ]
        ]
    ]
let aboutPageContent = 
    DockPanel.create [ 
        DockPanel.children [
            TextBox.create [ TextBox.text "About" ]
        ]
    ]

let tabs : IView list = [
    TabItem.create [
        TabItem.header "Home"
        TabItem.content homePageContent
    ]
    TabItem.create [
        TabItem.header "About"
        TabItem.content aboutPageContent
    ]
]

TabControl.create [
    TabControl.tabStripPlacement Dock.Left // Change this property to tell the app where to show the tab bar
    TabControl.viewItems tabs
]
```

**Set HostControl as content**

You can also include individual Elmish Controls as the content of your tabs by using the [ViewBuilder](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI.ControlCatalog/Avalonia.FuncUI.ControlCatalog/Views/MainView.fs#L36). Visit the [example](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI.ControlCatalog/Avalonia.FuncUI.ControlCatalog/Views/MainView.fs) to see it in action

```fsharp
// counter.fs
module Counter =
    type State = (* state definition *)
    type Msg = (* message definition *)
    let init = (* init definition *)
    let update state msg = (* update definition *)
    let view state dispatch = (* view definition *)

    // encapsule the Elmish architecture in this Host Control
    type Host() as this =
        inherit HostControl()
        do
            Elmish.Program.mkSimple (fun () -> init) update view
            |> Program.withHost this
            |> Program.run

// Program.fs
let aboutPageContent = 
    DockPanel.create [ 
        DockPanel.children [
            TextBox.create [ TextBox.text "About" ]
        ]
    ]
let tabs : IView list = [
    TabItem.create [
        TabItem.header "Counter"
        // use the ViewBuilder to be able to use the Counter module in a stand alone
        TabItem.content (ViewBuilder.Create<Counter.Host>([]))
    ]
    TabItem.create [
        TabItem.header "About"
        TabItem.content aboutPageContent
    ]
]

TabControl.create [
    TabControl.viewItems tabs
]
```

In the example above the `Counter` module defines a `HostControl` to allow that module to work by itself. This means you don't need to nest every view/control inside the main Elmish module of your app, this can help you reduce boilerplate and complexity in the main module of your application


# TextBlock

> *Note*: You can check the Avalonia docs for the [TextBlock](https://docs.avaloniaui.net/docs/controls/textblock) and [TextBlock API](http://reference.avaloniaui.net/api/Avalonia.Controls/TextBlock/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [TextBlock.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/TextBlock.fs)

The textblock control allows you to present text within the application.

### Usage

#### Basic usage

```fsharp
TextBlock.create [
    TextBlock.text <text-for-box>
]
```

#### Properties

You will often want to specify how you want the text to look and TextBlock implements a number of properties to that end

**Background** You can pass either a basic string or an IBrush instance for more control

```fsharp
TextBlock.create [
    TextBlock.background "red"
    TextBlock.text "Critical malfunction!"
]
```

**Foreground** To set the text color, you can again pass either a basic string or an IBrush instance

```fsharp
TextBlock.create [
    TextBlock.foreground "green"
    TextBlock.text "All systems operational."
]
```

**Font** The look of the font is specified by way of the fontFamily, fontSize, fontWeight and fontStyle properties

```fsharp
TextBlock.create [
    TextBlock.fontFamily font   // where font is an Avalonia.Media.FontFamily instance
    TextBlock.fontSize 24.0
    TextBlock.fontWeight Avalonia.Media.FontWeight.Bold
    TextBlock.fontStyle Avalonia.Media.FontStyle.Italic
    TextBlock.text "Entrance restricted."
]
```

**Padding** TextBlock allows you to set the padding in several ways

```fsharp
TextBlock.create [
    // using horizontal, vertical values
    TextBlock.padding (20.0, 10.0)
    // using left, top, right, bottom values 
    TextBlock.padding (5.0, 10.0, 15.0, 20.0)
    // using an Avalonia.Thickness struct
    TextBlock.padding thickness
    TextBlock.text "It's nice with some space."
]
```

**Text formatting** Several properties are available to adjust how the content of the TextBlock is formatted

```fsharp
TextBlock.create [
    TextBlock.lineHeight 16.0
    TextBlock.maxLines 4
    TextBlock.textWrapping Avalonia.Media.TextWrapping.Wrap
    TextBlock.textAlignment Avalonia.Media.TextAlignment.Center
    TextBlock.textTrimming Avalonia.Media.TextTrimming.WordEllipsis
    TextBlock.text "A longer paragraph could at times use some more formatting."
]
```


# TextBox

> *Note*: You can check the Avalonia docs for the [TextBox](https://docs.avaloniaui.net/docs/controls/textbox) and [TextBox API](http://reference.avaloniaui.net/api/Avalonia.Controls/TextBox/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [TextBox.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/TextBox.fs)

The textbox is a control that allows a user to input strings.

### Usage

#### Basic usage

```fsharp
TextBox.create [
    TextBox.text <text-for-box>
    TextBox.onTextChanged (fun newString ->
        // Do something with the changed string
    )
]
```

**Example**

Often you simply save the string in the state and use it for other things from there:

```fsharp
type State = {
    myString: string
}

type Msg =
    | ChangeMyString of string

let update msg state =
    match msg with
    | ChangeMyString newString ->
        { state with myString = newString }

let view state dispatch =
    TextBox.create [
        TextBox.text state.myString
        TextBox.onTextChanged (ChangeMyString >> dispatch)
    ]
```


# TimePicker

> *Note*: You can check the Avalonia docs for the [TimePicker](https://docs.avaloniaui.net/docs/controls/timepicker) and [TimePicker API](http://reference.avaloniaui.net/api/Avalonia.Controls/TimePicker/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [TimePicker.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/TimePicker.fs)

The TimePicker control allows the user to pick a time value.

### Usage

**Create a TimePicker**

```fsharp
TimePicker.create [
    TimePicker.header "Arrival Time"
]
```

**Change in 15 Minute Increments**

```fsharp
TimePicker.create [
    TimePicker.header "Arrival Time"
    TimePicker.minuteIncrement 15
]
```

**Choose a 12 or 24 Hour Clock**

For more information about the attribute values here you can check out the documentation for [TimeSpan](https://docs.microsoft.com/en-us/dotnet/api/system.timespan) and the [ClockIdentifier](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.timepicker.clockidentifier?view=winrt-19041#Windows_UI_Xaml_Controls_TimePicker_ClockIdentifier).

```fsharp
TimePicker.create [
    TimePicker.header "12 Hour Clock"
    TimePicker.selectedTime (TimeSpan(14, 30, 0))
    TimePicker.clockIdentifier "12HourClock"
]

TimePicker.create [
    TimePicker.header "24 Hour Clock"
    TimePicker.selectedTime (TimeSpan(14, 30, 0))
    TimePicker.clockIdentifier "24HourClock"
]
```


# ToggleButton

> *Note*: You can check the Avalonia docs for the [ToggleButton](https://docs.avaloniaui.net/docs/controls/togglebutton) and [ToggleButton API](http://reference.avaloniaui.net/api/Avalonia.Controls.Primitives/ToggleButton/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [ToggleButton.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Buttons/ToggleButton.fs)

If you are looking for a button to behave more like a checkbox you can use a `ToggleButton`. A `ToggleButton` toggles between checked and unchecked on click.

A `ToggleButton` is a subclasses of Button so they share all the same attributes as described on that documentation page. A `ToggleButton` behaves similar to a CheckBox and shares similar attributes like making tristate ToggleButtons.

> You need to `open Avaloina.Controls.Primatives` to access `ToggleButton` attributes.

### Usage

**Toggling for Checked/Unchecked**

```fsharp
ToggleButton.create [
    ToggleButton.isChecked state.checked
    // Returns a bool value
    ToggleButton.onIsPressedChanged (fun val -> OnChecked val |> dispatch)
]
```

**Handling Checked and Unchecked Differently**

```fsharp
ToggleButton.create [
    ToggleButton.onChecked (fun _ -> dispatch Enabled)
    ToggleButton.onUnchecked (fun _ -> dispatch Disabled)
]
```

**Tristate Toggling**

`ToggleButton.isChecked` can take values that are `bool`, `Nullable<bool>`, or `bool option`. When using tristate options however, you must use either `Nullable<bool>` or `bool option`. You can also handle each event state like above using `onChecked`, `onUncheked`, and `onIndeterminate`.

```fsharp
ToggleButton.create [
    // can be either true or false
    ToggleButton.isThreeState state.indeterminate
    // this value is required to be either a nullable boolean
    // or a boolean option
    ToggleButton.isChecked state.checked
    // Returns a Nullable<bool> value
    ToggleButton.onIsCheckedChanged (fun nullabelVal -> OnChecked val |> dispatch)
]
```


# ToggleSwitch

> *Note*: You can check the Avalonia docs for the [ToggleSwitch API](http://reference.avaloniaui.net/api/Avalonia.Controls/ToggleSwitch/) if you need more information.
>
> For Avalonia.FuncUI's DSL properties you can check [ToggleSwitch.fs](https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI/DSL/Buttons/ToggleSwitch.fs)

A `ToggleSwitch` is a switch that toggles between on (checked) and off (unchecked) states. This control functions similarly to a CheckBox but displays the content with an on/off slider instead.

### Usage

**Create a ToggleSwitch**

```fsharp
ToggleSwitch.create [
    ToggleSwitch.content "Title"
]
```

**Register State Change**

```fsharp
ToggleSwitch.create [
    ToggleSwitch.isChecked state.toggleSwitch
    ToggleSwitch.onIsPressedChanged (fun value -> SwitchToggled value |> dispatch)
]
```

**Handle state changes Separately**

```fsharp
ToggleSwitch.create [
    ToggleSwitch.content "Fullscreen"
    ToggleSwitch.onChecked (fun _ -> dispatch Fullscreen)
    ToggleSwitch.onUnchecked (fun _ -> dispatch Windowed)
]
```

**Tristate Toggling**

`ToggleSwitch.isChecked` can take values that are `bool`, `Nullable<bool>`, or `bool option`. When using tristate options however, you must use either `Nullable<bool>` or `bool option`. You can also handle each event state like above using `onChecked`, `onUncheked`, and `onIndeterminate`.

```fsharp
ToggleSwitch.create [
    // can be either true or false
    ToggleSwitch.isThreeState state.indeterminate
    // this value is required to be either a nullable boolean
    // or a boolean option
    ToggleSwitch.isChecked state.checked
    // Returns a Nullable<bool> value
    ToggleSwitch.onIsCheckedChanged (fun nullabelVal -> OnChecked val |> dispatch)
]
```


