Oxpecker DSL
Partas.Solid is a fork of Oxpecker.Solid and keeps its DSL. Attributes go in a constructor call, children go in a computation expression after it:
tag (attribute = value, ...) {
child
child
}
Attributes are easy to tell apart from children, and each element has a clear start and end, much like XML. To build attributes programmatically, for example from a list, spread an object onto the element with .spread.
Elements
Each HTML element is a class, and its attributes are optional constructor parameters. Attribute names that are F# keywords get an apostrophe: class', type', for', when'.
button (class' = "btn", type' = "button", title = "A plain button") { "Button" }
export function Cell_c1() {
return <button class="btn"
type="button"
title="A plain button">
Button
</button>;
}
Children
The computation expression after an element holds its children: strings, numbers and other elements, in any mix.
div () {
"Button label"
button () { "Button" }
span () { "Count:" }
5
}
An element with no children does not need the braces: input (type' = "checkbox"). Void elements such as input, br and img do not accept any.
Ordinary F# works around and inside the block. An if becomes a ternary in the JSX:
let name = "Solid"
div () {
p () { $"Hello, {name}!" }
if name.Length > 3 then
p () { "That is a long name." }
}
export function Cell_c3() {
return <div>
<p>
{concat("Hello, ", "Solid", "!")}
</p>
{("Solid".length > 3) ? (<p>
That is a long name.
</p>) : (undefined)}
</div>;
}
Embedded JSX
Embed raw JSX (Fable's JSX.jsx) through a small helper:
let inline toHtmlElement (func: string -> JSX.Element) (value: string) : HtmlElement =
unbox (func value)
div () {
toHtmlElement JSX.jsx "<button>Button</button>"
}
Lambda children
Some components, such as For, take a function as their child instead of elements.
ul () {
For.Keyed(each = [| "one"; "two"; "three" |]) {
yield fun item _ -> li () { $"Item {item}" }
}
}
Extension methods
Extension methods cover what constructor parameters cannot: spreads, custom and data-* attributes, style objects and refs.
div(style = "padding: .5em; border: 1px dashed gray").data("state", "ready").attr("aria-live", "polite") {
"This div has data-state and aria-live attributes."
}
export function Cell_c5() {
return <div style="padding: .5em; border: 1px dashed gray"
data-state="ready"
aria-live="polite">
This div has data-state and aria-live attributes.
</div>;
}
See extension methods for the full list.
