Firelight
The core package: F# bindings for Lit. Define web components with reactive properties, scoped styles and html templates.
Why use it
Web components are the browser's own component model. A custom element works in any page, alongside any framework or none. Lit takes away the boilerplate: you declare properties and return a template, and Lit updates only the parts of the page that changed.
Firelight lets you write those components in F#. Templates are F# interpolated strings, so the values and event handlers in them are ordinary typed F# code. The bindings themselves compile away: your component imports Lit directly, and there is no Firelight runtime to ship.
Example
A star rating. value is a reactive property that also reads and writes the
value attribute, the styles are scoped to the component, and choosing a star raises
a rating-changed event. The message below comes from plain JavaScript on this page
listening for that event.
module Snippets.Rating
open Fable.Core
open Fable.Core.JsInterop
open Browser.Types
open Firelight
open type Firelight.Lit
// Each star is a button named "n out of 5"; the one matching the rating is pressed.
let private star (n: int) (value: int) (select: unit -> unit) =
html
$"""<button class={if n <= value then "on" else ""} aria-label="{n} out of 5"
aria-pressed={n = value} @click={fun _ -> select ()}>{if n <= value then "★" else "☆"}</button>"""
/// <my-rating value="3"></my-rating>
/// Clicking a star sets `value` and raises a "rating-changed" event for the page to handle.
[<AttachMembers>]
type Rating() =
inherit LitElement()
static member properties =
PropertyDeclarations.create [
"value", PropertyDeclaration<int>(reflect = true)
]
static member styles =
css
$$"""
button { all: unset; cursor: pointer; font-size: 2rem; color: var(--muted); border-radius: 0.25rem; }
button.on { color: var(--accent); }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
"""
member val value = 0 with get, set
member this.Select(stars: int) =
this.value <- stars
this.dispatch (Event.customEvent ("rating-changed", stars))
override this.render() =
html $"""{[ for n in 1..5 -> star n this.value (fun () -> this.Select n) ]}"""
defineElement<Rating> "my-rating"
Pick a rating.
Install
dotnet add package Firelight
npm install lit
New to Firelight? The Get started tutorial creates an app from a template, then gives its component an attribute, an event, styles and a list.