Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: button.type should default to button, not submit? #178

Open
raquo opened this issue Nov 11, 2024 · 5 comments
Open

RFC: button.type should default to button, not submit? #178

raquo opened this issue Nov 11, 2024 · 5 comments

Comments

@raquo
Copy link
Owner

raquo commented Nov 11, 2024

HTML spec says that a <button> element without an explicitly specified type attribute should be interpreted to have type=submit.

This makes some amount of sense for applications that consist of HTML forms that are submitted with such buttons, but Laminar is primarily designed for SPA applications, where most buttons do not submit any html forms.

Forgetting to specify type=button leads to buttons that do the wrong thing – submit the html form they're in – instead of performing the onClick or other action that we expect of them. And the way we're building our apps, the helper function in which the button is defined may not know whether it will be rendered in a form or not, so if type=button is not specified, it may work initially if rendered outside of the form, but fail when the button is moved to inside a form.

Correctly specifying type=button results in a bit of extra boilerplate for the majority use case.


High-level web component libraries such as Shoelace generally default to type=button in their button components. Lower level libraries like React.js generally stick to the native HTML behaviour, i.e. have type=submit as a default.

I'm wondering if Laminar should also default to type=button, even if it's decidedly a low level library. The type=submit default just seems to be so counter-productive. I'm well aware of this default, and yet I still often forget to specify type=button.

For me personally, building SPAs, type=submit is a rare use case, so I always specify it explicitly. I don't make use of the default in the spec, and personally would be happy to not need to type out type=button on 90% of the buttons I create.

Yet at the same time, adding a special type=button default to Laminar could confuse people. While the various HTML docs and tutorials including MDN generally specify type=submit attribute explicitly when it's intended to submit a form, if you do follow some tutorial that omits type=submit and relies on it being the default, you would need to look at Laminar docs to find why your form is not submitting, which goes against Laminar's general advice that you should look at html docs because Laminar behaves the way html behaves.

Normally we could hope for the standard / spec to improve eventually, but this is HTML – it will never change such a fundamental default, no matter how broken it is.


I haven't yet decided one way or another, except that whatever we choose, will be the only default available in Laminar, with no conditions and no configuration.

I would like to hear your opinion – regardless of whether you're experienced in Laminar / frontend / DOM / HTML or not.

  • Would having type=button as default improve Laminar ergonomics for you?
  • Do you often use button without specifying its type, relying on the default?
  • How surprised and frustrated would you be to encounter this non-standard default in Laminar, if you didn't know it was there?
@j-mie6
Copy link

j-mie6 commented Nov 11, 2024

Personally, I've only used buttons with the type set to button; I'm in favour of this proposal.

Perhaps this could be mitigated with a separate button method, something like formButton or submit or formSubmit for instance to serve as a button with the "classic" HTML default?

@krestenlaust
Copy link

I believe it's best to follow the spec, otherwise what are we basing it on really. Maybe add another shorthand for button which is type=button

Are there ANY other applications where it would also make sense to deviate from HTML standard?

@raquo
Copy link
Owner Author

raquo commented Dec 2, 2024

@krestenlaust This is, indeed, in essence, a question of naming, specifically – which version gets the "good" button name, and which version gets the more verbose alternative name.

For example, we could alias button to create a button with the type=button preset, and submitButton for the HTML-spec behaviour.

Or, the other way – keep button to spec, and add some alias for type=button. But what could we possibly call it? buttonButton? nonSubmitButton? realButton? If we could find a good name for this, that could be one compromise worth taking. But, I'm not sure if there is a good name for it, because the underlying HTML concept – defaulting the button to a specialized type=submit variation – is bad.

Laminar names normally differ a bit from the underlying DOM names as described here, mostly to match Scala style, to avoid using a common variable name, and to avoid name conflicts, for example:

  • The width HTML attribute is called widthAttr, not width. If you do width <-- ... in Laminar, you're actually setting the CSS width prop. This is because in Laminar we have a single HTML-like namespace for HTML attrs / props / events, AND also CSS props, whereas in raw HTML and CSS those same-named attributes/props are used in very different ways.
  • The value HTML attribute in Laminar is called defaultValue (matching its DOM name, but different from its HTML attribute name), and we use the name value for the value HTML property. Context

In other low-level HTML libs, OTOH:

React.js famously made its onChange behave (almost) like the browser onInput event. Users who wanted original HTML-spec onChange behaviour could use onBlur, which is another HTML-spec event that is (almost) the same as the HTML-spec onChange event for practical purposes.

React did this because back then, the onInput event was pretty new, and did not work properly across all browsers, and they also felt that the HTML-spec onChange was misleadingly named. Now that onInput is widely supported, everyone believes that they should have simply called their polyfill onInput instead of onChange.

Of course, all these situations are unique, different from the current case in one way or another. For example, the React team should have had the expectation that the relevant browsers will eventually support onInput, whereas in our case, we're expecting that the button type=submit default will likely never change in the spec.

@raquo
Copy link
Owner Author

raquo commented Dec 2, 2024

We could also use submitButton name for the HTML-spec button, and some other name that is not button for "normal" buttons (but again, we would need to find a good name for that). On the plus side, that would avoid giving preference to one or the other, but on the other hand, users would be puzzled when they don't find the obvious button name.

For some precedent – we already do this naming pattern with style. The <style> tag is named styleTag, and the style attribute is named styleAttr, because we need a way to avoid naming collision, and because both of those are rarely used in Laminar, so we don't have a reason to give either of them a preference. And also because we want to use the style name available for any custom styling solutions.

Of course, button is way more popular than style, so it's a much harder sell to not use that name for anything.

@raquo
Copy link
Owner Author

raquo commented Dec 4, 2024

Btw here's another example of how following HTML spec can produce undesired results: #180 – that issue keeps tripping people, so we will eventually need a better way to set the value property of select elements, which will not be spec-compliant. Whether we'll special-case our implementation to make it "just work", or create a new custom API for that purpose, I don't know yet. There are pros and cons to either approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants