Skip to content

feat: let a LitElement take part in forms - #86

Open
OnurGumus wants to merge 1 commit into
fable-hub:mainfrom
OnurGumus:feat/form-associated
Open

OnurGumus wants to merge 1 commit into
fable-hub:mainfrom
OnurGumus:feat/form-associated

Conversation

@OnurGumus

Copy link
Copy Markdown
Contributor

Adds config.formAssociated to LitElement.init, so a [<LitElement>] can take part in the form it's inside.

[<LitElement("my-submit-button")>]
let SubmitButton () =
    let host, _ = LitElement.init (fun config -> config.formAssociated <- true)

    if isNull (box host?internals) then
        host?internals <- host?attachInternals ()

    html $"""<button type="button" @click={Ev(fun _ -> host?internals?form?requestSubmit ())}>Go</button>"""

Why

A form ignores a custom element unless the element's class has static formAssociated = true. Without it, attachInternals() still succeeds, but the internals have no form. Reading .form throws:

NotSupportedError: Failed to read the 'form' property from 'ElementInternals':
The target element is not a form-associated custom element.

Until now there was no way to set it from LitElement.init, so writing a custom input or submit button meant copying the whole LitElement attribute just to add one static getter.

What changes

  • LitConfig.formAssociated (default false), with a doc comment.
  • LitElementAttribute: when it's set, defines a static formAssociated getter on the class, next to the getters it already defines for properties and styles. Nothing changes for elements that don't set it.
  • Docs: a "Forms" section in docsrc/docs/web-components.md.

Tests

test/FormElementTest.fs, two tests:

  • the flag reaches the element's definition, and an element that didn't ask for it isn't form-associated;
  • a submit button that isn't a <button> submits the <form> it sits in.

With the getter removed, both fail (the second with the NotSupportedError above). dotnet build Fable.Lit.sln and npm test pass (39 tests).

🤖 Generated with Claude Code

A form ignores a custom element inside it unless the element's class has
static formAssociated = true. Without it, attachInternals() still succeeds
but the internals have no form: reading .form throws NotSupportedError.
There was no way to say it from LitElement.init, so a custom submit button
or input meant copying the whole LitElement attribute to add one getter.

config.formAssociated <- true defines that static getter on the class,
next to the ones already defined for properties and styles.

Two tests: the flag reaches the element definition only for an element
that asked for it, and a submit button that isn't a <button> submits the
form it is in. With the getter removed, both fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JordanMarr JordanMarr added the after-2.0 Considered after the 2.0 maintenance release (see #90) label Oct 19, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

after-2.0 Considered after the 2.0 maintenance release (see #90)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants