Example - HTMX

Falco.Htmx brings type-safe htmx support to Falco. It provides a complete mapping of all attributes, typed request data and ready-made response modifiers.

In this example, we'll demonstrate some of the more common htmx attributes and how to use them with Falco.

At this point, we'll assume you have reviewed the docs, other examples and understand the basics of Falco. We don't be covering any of the basics in the code review.

The code for this example can be found here.

Creating the Application Manually

> dotnet new falco -o HtmxApp
> cd HtmxApp
> dotnet add package Falco.Htmx

Layout

First we'll define a simple layout and enable htmx by including the script. Notice the strongly typed reference, HtmxScript.cdnSrc, which is provided by Falco.Htmx and resolves to the official CDN URL.

module View =
    let template content =
        Elem.html [ Attr.lang "en" ] [
            Elem.head [] [
                Elem.script [ Attr.src HtmxScript.cdnSrc ] [] ]
            Elem.body []
                content ]

Components

A nice convention when working with Falco.Markup is to create a Components module within your View module. We'll define a few components here.

All of the htmx attributes and properties are mapped within the Hx module. Wherever a limited scope of options exist, strongly typed references are provided. For example, Hx.swapOuterHtml is a strongly typed reference to the hx-swap attribute with the value outerHTML. This is a great way to avoid typos and ensure that your code is type-safe.

module View =
    // Layout ...

    module Components =
        let clicker =
            Elem.button
                [ Hx.get "/click"
                  Hx.swapOuterHtml ]
                [ Text.raw "Click Me" ]

        let resetter =
            Elem.div [ Attr.id "wrapper" ] [
                Text.h2 "Way to go! You clicked it!"
                Elem.br []
                Elem.button
                    [ Hx.get "/reset"
                      Hx.swapOuterHtml
                      Hx.targetCss "#wrapper" ]
                    [ Text.raw "Reset" ] ]

The clicker component is a simple button that will send a GET request to the server when clicked. The response will replace the button with the resetter component which will be rendered in the same location and can be used to restore the original state.

Handlers

Next we define a couple basic handlers to handle the requests for the original document and ajax requests.

module App =
    let handleIndex : HttpHandler =
        let html =
            View.template [
                Text.h1 "Example: Click & Swap"
                View.Components.clicker ]

        Response.ofHtml html

    let handleClick : HttpHandler =
        Response.ofHtml View.Components.resetter

    let handleReset : HttpHandler =
        Response.ofHtml View.Components.clicker

You can see that the handleClick and handleReset handlers are simply returning the resetter and clicker components respectively. The handleIndex handler is returning the full HTML document with the clicker component.

Web Server

To finish things off, we'll map our handlers to the expected routes and initialize the web server.

[<EntryPoint>]
let main args =
    let wapp = WebApplication.Create()

    let endpoints =
        [
            get "/" App.handleIndex
            get "/click" App.handleClick
            get "/reset" App.handleReset
        ]

    wapp.UseRouting()
        .UseFalco(endpoints)
        .Run()
    0 // Exit code

Wrapping Up

That's it! You now have a simple web application that uses htmx to swap out components on the page without a full page reload. This is just the beginning of what you can do with htmx and Falco. You can use the same principles to create more complex interactions and components.

For more information about the htmx integration, check out the Falco.Htmx repository. It contains a full list of all the attributes and properties that are available, as well as examples of how to use them.

Go back to docs home