Fable.Lit.Dsl
1.0.1
dotnet add package Fable.Lit.Dsl --version 1.0.1
NuGet\Install-Package Fable.Lit.Dsl -Version 1.0.1
<PackageReference Include="Fable.Lit.Dsl" Version="1.0.1" />
<PackageVersion Include="Fable.Lit.Dsl" Version="1.0.1" />
<PackageReference Include="Fable.Lit.Dsl" />
paket add Fable.Lit.Dsl --version 1.0.1
#r "nuget: Fable.Lit.Dsl, 1.0.1"
#:package Fable.Lit.Dsl@1.0.1
#addin nuget:?package=Fable.Lit.Dsl&version=1.0.1
#tool nuget:?package=Fable.Lit.Dsl&version=1.0.1
Fable.Lit.Dsl
A collection of expressive, type-safe DSLs for building UI with Fable.Lit. This repo currently includes:
- Fable.Lit.Dsl - a clean, idiomatic way to write Lit templates in F#
- Fable.Lit.Dsl.Shoelace - typed components, attributes, and events for the Shoelace Web Component library
More DSLs may be added over time.
Related Projects
- Fable.Lit - core F# bindings for Lit: https://github.com/fable-compiler/Fable.Lit
Installation
Add the packages to your project:
dotnet add package Fable.Lit.Dsl
dotnet add package Fable.Lit.Dsl.Shoelace
If using Shoelace, register its assets at app startup:
open Fable.Core.JsInterop
open Fable.Lit.Dsl.Shoelace
// Set the base path for Shoelace assets (icons, etc.)
Shoelace.setBasePath()
// Import the components you need
Shoelace.startImports [|
importDynamic Shoelace.Asset.Button
importDynamic Shoelace.Asset.Input
importDynamic Shoelace.Asset.Dialog
// ... add more as needed
|]
HTML DSL
The HTML DSL provides a natural, structured way to write Lit templates in F# without stringly-typed markup.
Example
open Fable.Lit.Dsl
view {
h1 { "Hello, world!" }
p { "This is the Fable.Lit HTML DSL." }
button {
disabled false
onClick (fun _ -> dispatch Increment)
"Click me"
}
}
Builders
view { }- Use at the top level of components. Returns aTemplateResultfor rendering.template { }- Use for nested fragments inside elements. Returns aNode.el "tag-name" { }- Create custom elements with any tag name.
Custom Elements with el
Use el for one-off custom elements or web components:
view {
el "my-custom-element" {
attr "theme" "dark"
prop "config" {| rows = 10; cols = 5 |}
boolAttr "enabled" true
on "custom-event" (fun e -> dispatch (CustomEvent e))
"Child content"
}
}
Available attribute helpers:
attr "name" value- String attributeboolAttr "name" true- Boolean attribute (present when true, absent when false)prop "name" value- JavaScript property (for complex values or web component properties)on "event-name" handler- Event handler
Fragments with template
Use template when you need to return multiple sibling elements without a wrapper element. This is similar to React fragments (<>...</>).
/// Returns multiple elements without a wrapper div
let userInfo (user: User) =
template {
dt { "Name" }
dd { user.Name }
dt { "Email" }
dd { user.Email }
}
let mainView model =
view {
h1 { "User Details" }
dl {
// Inserts dt/dd pairs directly into the dl, no wrapper element
userInfo model.User
}
}
In most cases, wrapping content in a div is fine. Use template only when an extra wrapper element would break your HTML structure or CSS styling (like inside <dl>, <table>, <ul>, or flex/grid containers where extra elements affect layout).
Highlights
- Strongly-typed attributes and events
- Natural F# computation expression syntax
- No raw HTML strings
- Works seamlessly with Lit components and custom elements
Shoelace DSL
Typed, ergonomic bindings for the Shoelace Web Component library.
Example
open Fable.Lit.Dsl
open Fable.Lit.Dsl.Shoelace
view {
slButton {
variantPrimary
onClick (fun _ -> dispatch Save)
"Save"
}
slInput {
label' "Email"
placeholder' "you@example.com"
onSlInput (fun e -> dispatch (EmailChanged e))
}
slDialog {
label' "Confirm"
open' model.ShowDialog
onSlRequestClose (fun _ -> dispatch CloseDialog)
p { "Are you sure?" }
}
}
Highlights
- All Shoelace components supported (
slButton,slInput,slDialog,slDrawer, etc.) - Typed properties (
variant,size,disabled',open',label', etc.) - Typed events (
onSlChange,onSlInput,onSlShow,onSlHide, etc.) - Works alongside the HTML DSL
Common Shoelace Properties
// Variants
variantPrimary // or: variant "primary"
variantSuccess
variantDanger
variantWarning
variantNeutral
// Sizes
sizeSmall // or: size "small"
sizeMedium
sizeLarge
// States
disabled' true
loading true
open' true
checked' true
clearable true
// Values
value' "text"
label' "Label"
placeholder' "Placeholder"
helpText "Help text"
Common Shoelace Events
onSlChange handler // Value changed (after interaction)
onSlInput handler // Real-time input
onSlShow handler // Element starting to show
onSlAfterShow handler // Element shown, animations complete
onSlHide handler // Element starting to hide
onSlAfterHide handler // Element hidden, animations complete
onSlRequestClose handler // Close requested (dialogs/drawers)
onSlSelect handler // Menu item selected
Extensibility: Build Your Own DSL
The DSL system is intentionally modular. You can create your own DSL for any Web Component library.
Minimal Example
module MyComponents
open Fable.Lit.Dsl
// Define elements for your web components
let fancyCard = ElementBuilder("fancy-card")
let fancyButton = ElementBuilder("fancy-button")
// Define typed properties
let cardTitle (text: string) = prop "cardTitle" text
let elevation (level: int) = prop "elevation" level
// Define typed events
let onFancyClick (handler: obj -> unit) : Attr = Event("fancy-click", handler)
Usage:
open MyComponents
view {
fancyCard {
cardTitle "Welcome"
elevation 2
fancyButton {
onFancyClick (fun _ -> dispatch Click)
"Click me"
}
}
}
You can extend:
- Components (using
ElementBuilder) - Attributes (using
attr) - Properties (using
prop) - Events (using
Event) - Boolean attributes (using
boolAttr)
This repo models the pattern used by the HTML and Shoelace DSLs.
More Examples
Conditional Rendering
view {
h2 { "Dashboard" }
if model.IsLoading then
slSpinner { }
else
div {
p { $"Welcome, {model.Username}!" }
}
}
Lists
view {
ul {
for item in model.Items do
li { item.Name }
}
}
Mixing HTML and Shoelace
view {
header {
class' "app-header"
h1 { "My App" }
}
main {
slCard {
div {
slot' "header"
h3 { "Stats" }
}
p { $"Count: {model.Count}" }
div {
slot' "footer"
slButton {
variantPrimary
onClick (fun _ -> dispatch Increment)
"Increment"
}
}
}
}
}
Using Refs
let inputRef = ref Unchecked.defaultof<Browser.Types.HTMLInputElement>
view {
slInput {
bindRef (fun el -> inputRef.Value <- el :?> _)
label' "Focus me"
}
slButton {
onClick (fun _ -> inputRef.Value.focus())
"Focus Input"
}
}
Embedding Raw Lit Templates
open Lit
view {
h1 { "Mixed Content" }
// Embed an existing Lit template
lit (html $"<p>Raw Lit template</p>")
// Or raw HTML (use sparingly)
rawHtml "<p>Raw HTML string</p>"
}
Roadmap
The DSL system is intentionally modular, and this repo may grow over time as more UI libraries adopt Web Components.
Potential Future DSLs
- FluentUI DSL - Microsoft's Fluent Web Components
- FAST DSL - FAST's design tokens and component model
- Material Web DSL - Google's Material Web Components
- Community DSLs - Anyone can build a DSL package for their preferred component library
Future Improvements
- Additional typed attributes and events
- Expanded examples and documentation
- Potential integration with design-token systems
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Fable.Lit (>= 1.4.2)
- FSharp.Core (>= 6.0.4)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Fable.Lit.Dsl:
| Package | Downloads |
|---|---|
|
Fable.Lit.Dsl.Shoelace
Shoelace web component bindings for Fable.Lit.Dsl. Provides strongly-typed F# DSL elements for building Shoelace-based UIs with Fable.Lit. |
GitHub repositories
This package is not used by any popular GitHub repositories.