Getting started
Custom Elements & Attributes
FSharp.ViewEngine covers all standard HTML elements and attributes, but you may need custom ones for web components or non-standard attributes.
Custom Elements
el
Use Html.el to create a custom element with children. This is useful for web components:
open FSharp.ViewEngine
open type Html
el "my-component" {
_class "container"
p { "Hello from a web component!" }
}
Renders:
<my-component class="container">
<p>Hello from a web component!</p>
</my-component>
elVoid
Use Html.elVoid to create a custom self-closing (void) element:
elVoid "my-icon" {
_attr("name", "star")
_attr("size", "24")
}
Renders:
<my-icon name="star" size="24">
Nested Web Components
Custom elements can be nested just like regular elements:
el "my-card" {
_attr("variant", "outlined")
el "my-card-header" {
h2 { "Card Title" }
}
el "my-card-body" {
p { "Card content goes here." }
}
el "my-card-footer" {
button { _onclick "handleClick()"; "Action" }
}
}
Custom Attributes
_attr
Use Html._attr to add any attribute not covered by the built-in helpers.
Key-value attribute
div {
_attr("my-custom-attr", "value")
"Content"
}
Renders:
<div my-custom-attr="value">Content</div>
Boolean attribute
Pass only the name to render a valueless (boolean) attribute:
div {
_attr "my-flag"
"Content"
}
Renders:
<div my-flag>Content</div>
Combining with Built-in Attributes
Custom attributes work alongside all built-in attributes:
el "sl-button" {
_attr("variant", "primary")
_attr("size", "large")
_attr "pill"
_onclick "handleClick()"
_class "my-button"
"Click Me"
}
Renders:
<sl-button variant="primary" size="large" pill onclick="handleClick()" class="my-button">
Click Me
</sl-button>
Extending the Html Type
F# supports type extensions which let you add your own elements and attributes to the Html type. This is useful for project-specific conventions or design system components.
Adding Custom Elements
open FSharp.ViewEngine
type Html with
static member val myCard = TagBuilder("my-card") with get
static member val myIcon = VoidBuilder("my-icon") with get
Then use them just like built-in elements:
open type Html
myCard {
_class "shadow-lg"
h2 { "Title" }
p { "Card content" }
}
myIcon { _attr("name", "star") }
Adding Custom Attributes
open FSharp.ViewEngine
type Html with
static member inline _theme (v: string) = { Name = "data-theme"; Value = ValueSome v }
static member inline _variant (v: string) = { Name = "variant"; Value = ValueSome v }
static member inline _loading = { Name = "data-loading"; Value = ValueNone }
Then use them alongside built-in attributes:
open type Html
div {
_theme "dark"
_variant "outlined"
_loading
"Content"
}
Design System Example
You can build a full design system module with reusable elements and attributes:
open FSharp.ViewEngine
type Ds =
static member val alert = TagBuilder("ds-alert") with get
static member val badge = TagBuilder("ds-badge") with get
static member val tooltip = TagBuilder("ds-tooltip") with get
static member inline _severity (v: string) = { Name = "severity"; Value = ValueSome v }
static member inline _placement (v: string) = { Name = "placement"; Value = ValueSome v }
static member inline _dismissible = { Name = "dismissible"; Value = ValueNone }
open type Html
open type Ds
alert {
_severity "warning"
_dismissible
"This is a warning message."
}
tooltip {
_placement "top"
button { "Hover me" }
}
Shoelace Example
Here's a more complete example using Shoelace web components:
el "sl-dialog" {
_attr("label", "Confirm")
_attr "open"
p { "Are you sure?" }
div {
_slot "footer"
el "sl-button" {
_attr("variant", "primary")
_onclick "this.closest('sl-dialog').hide()"
"Confirm"
}
}
}