Buttons: submit, reset and button
Three button types, one attribute, and a default that causes more accidental submissions than any other rule in HTML.
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
Concept
HTML has two ways to make a button: the button element and input with a button type. The button element is better in almost every case, because it can contain markup - an icon, a span, formatted text - while an input can only carry a plain string.
The three types
| Type | Does |
|---|---|
submit | Validates and submits the form. The default inside a form. |
reset | Clears every field back to its initial value. |
button | Does nothing on its own. For scripted actions. |
<button type="submit">Send application</button>
<button type="reset">Clear the form</button>
<button type="button" id="preview">Preview</button>The default that catches everyone
A button with no type inside a form defaults to type="submit". So this innocent looking markup submits the form every time it is pressed:
<form action="/save" method="post">
<input name="title">
<button onclick="addRow()">Add another row</button> <!-- submits! -->
</form>The script runs, then the form submits and the page navigates away. The usual symptom is my button works for a split second and then the page reloads.
<button type="button" onclick="addRow()">Add another row</button>Write type on every button. It is two words and it removes an entire category of bug.
button versus input
<!-- can contain markup -->
<button type="submit">
<svg aria-hidden="true">...</svg>
<span>Save changes</span>
</button>
<!-- plain text only, from the value attribute -->
<input type="submit" value="Save changes">Use button. The only historic reason to prefer input was consistency in very old browsers, which no longer matters.
Named submit buttons
A submit button can carry a name and a value, and only the button actually pressed is submitted. This is a clean way to give one form two outcomes without any JavaScript.
<form action="/post" method="post">
<textarea name="body"></textarea>
<button type="submit" name="action" value="draft">Save as draft</button>
<button type="submit" name="action" value="publish">Publish</button>
</form>The server receives action=draft or action=publish and branches on it.
Overriding the form from a button
A submit button can override several of the form attributes:
<button type="submit" formaction="/save-draft">Save draft</button>
<button type="submit" formmethod="get">Preview</button>
<button type="submit" formnovalidate>Save without checking</button>formnovalidate is the genuinely useful one: it lets a Save draft button skip validation while Publish enforces it.
Why reset is almost always wrong
type="reset" clears the whole form with no confirmation and no undo. It sits next to the submit button, looks identical, and destroys ten minutes of typing when pressed by mistake. Nobody wants it - readers who want to start again close the tab.
Leave it out. If a form genuinely needs a clear action, make it a scripted button with a confirmation step.
Disabled buttons
A disabled submit button is a common pattern and a poor one. It is not focusable, so a keyboard user cannot reach it to find out why it is disabled; screen readers may skip it entirely; and the reader is given no explanation.
<!-- better: always enabled, explains the problem on submit -->
<button type="submit">Create account</button>Let the reader press it and show them what is wrong. If a button must be disabled, keep it focusable and describe the condition:
<button type="submit" aria-disabled="true" aria-describedby="why-disabled">
Create account
</button>
<p id="why-disabled">Accept the terms before creating an account.</p>aria-disabled announces the state without removing the element from the tab order; the script then ignores the click.
Buttons that are not buttons
<!-- wrong: not focusable, no keyboard activation, no role -->
<div class="btn" onclick="save()">Save</div>
<!-- wrong: a link that navigates nowhere -->
<a href="#" onclick="save()">Save</a>
<!-- right -->
<button type="button" onclick="save()">Save</button>A real button gives you focusability, activation with both Enter and Space, the correct role, and disabled state handling. Recreating all of that on a div takes twenty lines of script and is usually done wrong.
Important rules
- A
buttoninside a form defaults totype="submit". - Only the pressed submit button is submitted, and only if it has a
name. Enterin a text field activates the first submit button in the form.- Buttons are focusable by default; do not add
tabindex. - A
buttonmust not contain interactive content such as a link or another button. type="reset"resets to the initial values, not to empty.
Common mistakes
- Omitting
typeand submitting a form by accident. - Keeping a reset button next to submit.
- Using a
divor a dead link as a button. - Disabling the submit button until the form is valid, with no explanation of why.
- Icon only buttons with no accessible name.
- Two submit buttons with no
name, so the server cannot tell which was pressed.
Best practices
- Always write
type. - Use the
buttonelement, notinput. - Label buttons with a verb and an object: Send enquiry, not Submit.
- Give icon only buttons an
aria-labeland mark the iconaria-hidden. - One primary action per form, visually distinct from secondary actions.
- Use
formnovalidatefor a save draft action. - Keep tap targets at least forty four pixels tall.
Practice
- Put a button with no
typeinside a form with a click handler and observe the page reload. Fix it. - Build a form with Save draft and Publish buttons sharing one name, and branch on the value.
- Add
formnovalidateto the draft button and confirm required fields no longer block it. - Replace a
divbased button with a real one and list everything you gained.