A button inside a form can submit that form when its type is omitted; type=button is for an action that does not submit.
HTML button type: make every form action explicit
When it earns its place
A reviewer can open a short policy note while filling an inspection report. That disclosure must not send the unfinished report, so its button declares type=button and targets a native popover. The final action declares type=submit. This distinction matters after a template change: moving an untyped button into a form can silently turn a harmless-looking control into a submission trigger. The server still treats a submitted report as untrusted input and checks the reviewer's permission.
<form action="/inspections/I-47/reports" method="post">
<label for="seal-note">Seal inspection note</label>
<textarea id="seal-note" name="note" required></textarea>
<button type="button" popovertarget="seal-policy">Read seal policy</button>
<button type="submit">Submit inspection report</button>
</form>
<div id="seal-policy" popover><p>Record a broken seal before dispatch.</p></div>Browser boundary
The popover button changes local interface state; it does not save data. Explicit button types also clarify intent for maintainers, but they do not prevent duplicate POST requests or replace backend idempotency where it is needed.
Cost and maintenance
Native button and popover behavior require no widget dependency. The main cost of an omitted type is accidental submission, which can waste a user's work or create duplicate records if the backend is not defensive.
Common Mistakes
- Do not leave a non-submit button's type implicit inside a form.
- Do not use type=button for the actual form submission unless script submits it deliberately.
- Do not mistake a disabled submit button for a server-side duplicate-request guard.
Connected lessons
- HTML link versus button: navigation and actions have different contracts
- HTML popover: show dismissible nonmodal help with a button
- HTML forms: choose GET for retrieval and POST for a state change
