whatwg / html

HTML Standard

Home Page:https://html.spec.whatwg.org/multipage/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: allow a mode of form.submit() that behaves like clicking a submit button

domenic opened this issue · comments

Right now, the following snippets of code behave differently:

form.submit();
const button = document.createElement('input');
button.type = 'submit';
form.append(button);
button.click();
button.remove();

Per https://html.spec.whatwg.org/#concept-form-submit, the second one gets a lot more useful behaviors: interactive validation, submit events, and the potential of replacement-enabled navigation when the document is not yet completely loaded.

Wouldn't it be nice if we could do

form.submit({ interactive: true });

or similar? (Bikeshed the name at your leisure.)

This is of special concern to folks trying to create custom form controls that behave like submit buttons, or for any attempts to explain the platform's elements in terms of imperative constructs.

Credit to @manucorporat for this idea; he pointed out that Ionic is currently using the hacky workaround for their custom submit button. That makes me sad and it would be nice if we could help them not do that.

/cc @tkent-google @rniwa @smaug---- @travisleithead for implementer thoughts.

Thanks Domenic for introducing the proposal!

To add a little more context, the hack is required because, even so we have a <button> for accessibility reasons, it is inside the shadow dom of ion-button component, making it unable to submit the form.

Seems like a good idea although maybe adding a new method would be cleaner since this is really a request to submit if the validation had passed. Another thing to consider is some aspects of it should be configurable. e.g. it's odd that the flag named interactive would trigger the firing of submit event.

I think some of this is handled by HTMLFormElement.reportValidity().

It'd be nice if this can also support the case of having button[value] as a submitter.

GitHub has a similar hacky submit function as well, but it takes in an additional optional button argument to ensure we can retain the value when submitting the form. It's used for binding keyboard shortcuts on these buttons, for example:

image

@rniwa agreed! and adding a new method would also make it easier to detect when this new feature is available

This sounds a good feature. I'll implement this in Chrome if this is standardized.
I agree with rniwa. We should have another function with a better name.

I agree with @muan that this should also have a submitter argument, if we're going to expose this primitive anyway. The slight complication that brings is some verification that it's indeed an okay submit button for the form.

Extending what @muan said, it would be great to be able to simulate what a:
<button type="reset"> do, so maybe a "type" arguments that defaults to "submit" makes sense too:

(tentative names)

form.requestSubmit({
   type: "reset", // defaults to "submit"
   value: "somevalue", // defaults to undefined
   name: "somename", // defaults to undefined
})

equivalent to:

<button type="reset" name="somename" value="somevalue">

Submits without extra config:

form.requestSubmit()

equivalent to:

<button type="submit">

thoughts about what this hypothetical method should return?

Submitting is a primitive (taking a submitter), doesn't return anything, but you could imagine returning details about the resulting state: https://html.spec.whatwg.org/#concept-form-submit.

Resetting is a different primitive (does not take arguments), also doesn't return anything: https://html.spec.whatwg.org/#concept-form-reset.

I think that means we want two methods here. Return values could make sense, but would probably delay things somewhat as we'd have to make sure that the return value is what we want long term (returning undefined for now and upgrading later is also an option).

@annevk you right!
actually, HTMLFormElement already has a reset() method that emits a cancellable ResetEvent, so we are fine.

(returning undefined for now and upgrading later is also an option)

absolutely, no need to make the proposal more complicated than it should be. There are already good ways to collect the submitted values

(tentative)

// equivalent to <input type="submit">
form.requestSubmit();

// equivalent to <input type="submit" name="somename" value="somevalue">
form.requestSubmit({
   value: "somevalue",
   name: "somename"
});

I'd make it take an actual element as that's the underlying primitive.

This seems like a great feature. Glad it can fix hacky workarounds in at least GitHub and Ionic (and probably others). Edge team supports and would also be willing to ship.

Now we have formdata event and we can add arbitrary entries with it. We don't need flexibility to specify value and name with the proposed API.

So, we should start with

void requestSubmit(HTMLElement? submitterButton);

It triggers submit with submitterButton as submitter and false as submitted from submit() method flag, which means triggers interactive form validation and fires submit event.

What do you think?

Yeah, that's the shape I want, except the IDL should be (optional arguments should use undefined, not null in JavaScript):

void requestSubmit(optional HTMLElement submitterButton);

What if you don't pass a submit button (i.e., <input type=image>, <input type=submit>, <button type=submit></button>), throw?

What about reset, we'd leave that alone for now?

What if you don't pass a submit button (i.e., , , ), throw?

Looking at https://html.spec.whatwg.org/#concept-form-submit it seems like the assumption is that submitter is a form-associated element. I think that's probably the right restriction for now.

Later, we can consider opening it up to form-associated custom elements as well, although for full parity it seems like we might need an additional way to say if the form-associated custom element "is a submit button", and thus its formmethod/formenctype/formaction attributes should be consulted.

What about reset, we'd leave that alone for now?

I'm not sure there's any value in exposing #concept-form-reset vs. just the existing reset() method. The reset method is just a wrapper around concept-form-reset plus a reentrancy guard. (Honestly, it may be a bug that that reentrancy guard is only in reset(), and not in #concept-form-reset.)

What if you don't pass a submit button (i.e., , , ), throw?

Looking at https://html.spec.whatwg.org/#concept-form-submit it seems like the assumption is that submitter is a form-associated element. I think that's probably the right restriction for now.

IMO, we should start with a stricter rule, and loosen it if necessary. So, the function should throw a NotSupportedError (is it a right one?) if submitterButton is not a right control type or is not associated to the context form element.

Later, we can consider opening it up to form-associated custom elements as well, although for full parity it seems like we might need an additional way to say if the form-associated custom element "is a submit button", and thus its formmethod/formenctype/formaction attributes should be consulted.

I think we can create the submit button behavior with the current form-associated custom element proposal and requestSubmit().

class SubmitElement extends HTMLElement {
   ...
   handleClick() {
     this.#internals.setFormValue(this.getAttribute('value'));
     this.#internals.form.requestSubmit(this);  // UA consults formmethod/formenctype/formaction attributes of this element.
     this.#internals.setFormValue(null);
  }
}

IMO, we should start with a stricter rule, and loosen it if necessary. So, the function should throw a NotSupportedError (is it a right one?) if submitterButton is not a right control type or is not associated to the context form element.

That works for me. Good catch on checking its form owner; we should definitely do that.

I think we can create the submit button behavior with the current form-associated custom element proposal and requestSubmit().

So this would require first losening the requirement so that "the right control type" includes any form-associated custom element, right?

This also doesn't allow the implicit submission behavior of https://html.spec.whatwg.org/#implicit-submission . But maybe that is a good thing; I think most web developers hate that feature.

Otherwise I agree that this suffices. Very nice. Clever trick with the setting value before/after.

// UA consults formmethod/formenctype/formaction attributes of this element.

I missed formnovalidate, by the way.