Skip to content

Tag Interfaces

Every tag in Partas.Solid is a type, and what a tag can do comes from the interfaces it implements: HtmlContainer takes children, HtmlTag takes the global HTML attributes and the extension methods. Your own components use the same interfaces, usually by inheriting a tag that already has them:

[<Erase>]
type MyButton() =
    inherit button() // every button attribute, children, and the extension methods

Foundation interfaces

InterfaceWhat it gives you
HtmlElementThe base. Anything that implements it can be a child of another element.
HtmlTagInherits HtmlElement. Adds the global HTML attributes, events and the extension methods.
HtmlContainerInherits HtmlElement. Lets the type take children in a { } block, and adds a children property.
FlowContainer<'A>Inherits HtmlElement. Like HtmlContainer, but children must be of type 'A.

Derived interfaces

InterfaceInheritsUsed for
RegularNodeHtmlTag, HtmlContainerAn element with attributes and children, such as div.
VoidNodeHtmlTagAn element with attributes and no children, such as input or br.
FlowNode<'A>HtmlTag, FlowContainer<'A>An element with attributes whose children are limited to 'A.
FragmentNodeHtmlContainerRenders as a JSX fragment, <></>. Fragment() implements it.

Switch, for example, is a FlowContainer<IMatch>, so the compiler only accepts Match children inside it.

Child lambda providers

Some components take a function as their child: For passes it each item and its index. The child lambda provider interfaces type that function:

InterfaceThe child is
ChildLambdaProvider<'P1>'P1 -> #HtmlElement
ChildLambdaProvider2<'P1, 'P2>'P1 -> 'P2 -> #HtmlElement
ChildLambdaProvider3<'P1, 'P2, 'P3>a function of three arguments
ChildLambdaProvider4<'P1, 'P2, 'P3, 'P4>a function of four arguments
ChildLambdaProviderStrict<'P1, 'Children>'P1 -> 'Children
ChildLambdaProviderStrict2 to 4the same, with two to four arguments

The strict variants fix the return type as well as the arguments. For.Keyed implements ChildLambdaProvider2<'T, Accessor<int>>, so its child is fun item index -> .... Repeat<'T> implements ChildLambdaProviderStrict<int, 'T>.

You pass the function with yield:

For.Keyed(each = items) {
    yield fun item index -> li () { item }
}

Implement one of these interfaces on your own component to take a function child. Inside the component, props.children holds the function. Unbox it to its F# type and call it:

[<Erase>]
type Toggle() =
    inherit div()
    interface ChildLambdaProvider<Accessor<bool>>

    [<SolidTypeComponent>]
    member props.View =
        let on, setOn = createSignal false
        let renderChild: Accessor<bool> -> HtmlElement = unbox props.children

        div (style = "display: flex; gap: .5rem; align-items: center") {
            button (onClick = fun _ -> setOn (not (on ()))) { "Flip" }
            renderChild on
        }
export function Toggle(props) {
    const PARTAS_OTHERS = omit(props, "children");
    const patternInput = createSignal(false);
    const on = patternInput[0];
    let renderChild;
    const clo = props.children;
    renderChild = (clo);
    return <div style="display: flex; gap: .5rem; align-items: center">
        <button onClick={(_arg) => {
                patternInput[1](!on());
            }}>
            Flip
        </button>
        {renderChild(on)}
    </div>;
}
Toggle() {
    yield fun on -> span () { if on () then "ON" else "OFF" }
}

For a function of two or more arguments, unbox the children to a System.Func, because Solid calls it with all of its arguments at once:

let renderChild: System.Func<Accessor<string>, (string -> unit), HtmlElement> = unbox props.children
renderChild.Invoke(value, setValue)

Polymorph

Polymorph lives in Partas.Solid.Polymorphism and inherits HtmlTag. It is for components whose rendered element the caller picks, such as Kobalte's. It adds an .as' extension that takes a tag or a tag value.

See Polymorphism and Kobalte.

Edit this page