Buttons (<button>)
The <button> element is the standard way to create a clickable control —
inside a form, or anywhere on the page. It's more flexible than
<input type="button"> because it can contain arbitrary HTML (icons, bold
text, multiple lines) instead of only a plain string. The one detail that
trips up almost every beginner: inside a <form>, a button's default
behavior is to submit that form, whether you meant it to or not.
The Three Button Types
The type attribute controls what a button does when clicked. There are
three values, and getting this right avoids one of the most common form
bugs.
type | Behavior inside a <form> |
|---|---|
| Submits the enclosing form — triggers validation and a page navigation/fetch. |
| Resets every field in the form back to its initial value. Rarely a good idea in modern UX. |
| Does nothing on its own — just fires a |
button-types.html
<form> <input type="text" name="query" /> <!-- Submits the form --> <button type="submit">Search</button> <!-- Clears all fields --> <button type="reset">Clear</button> <!-- Does nothing until JS adds a listener --> <button type="button" id="toggle-filters">Show filters</button> </form>
Why type="button" Matters
If you omit type entirely, a <button> inside a form defaults to
submit. This is a very common source of bugs: a "show more" or "toggle"
button meant to run a bit of JavaScript accidentally submits the whole
form instead, reloading the page and losing all the user's input.
accidental-submit.html
<!-- BUG: clicking this reloads the page because the button --> <!-- defaults to type="submit" inside the <form> --> <form id="signup-form"> <input type="email" name="email" required /> <button onclick="showTooltip()">?</button> <button type="submit">Sign up</button> </form> <!-- FIX: be explicit --> <form id="signup-form"> <input type="email" name="email" required /> <button type="button" onclick="showTooltip()">?</button> <button type="submit">Sign up</button> </form>
type="button" explicitly. Don't rely on memorizing the default — it's easy to forget, and the failure mode (silent form submission) is confusing to debug.<button> vs <input type="submit">
Both submit a form and both can be styled identically with CSS, so the choice mostly comes down to what content the button needs to hold.
<button> | <input type="submit"> | |
|---|---|---|
Content | Any HTML — icons, | Plain text only, via the |
Default type |
| Always |
Modern preference | Preferred — more flexible markup | Still valid, used less often today |
button-vs-input.html
<!-- <button> can hold rich content --> <button type="submit"> <img src="/icons/cart.svg" alt="" width="16" height="16" /> Add to Cart </button> <!-- <input type="submit"> is text-only --> <input type="submit" value="Add to Cart" />
Disabled Buttons
A disabled button can't be clicked, focused, or included in form
submission. It's commonly toggled with JavaScript — for example, disabling
a submit button until required fields are filled in, or while an async
request is in flight to prevent duplicate submissions.
disabled-button.html
<button type="submit" id="submit-btn" disabled>Submit</button>
<script>
const form = document.querySelector('form');
const submitBtn = document.getElementById('submit-btn');
form.addEventListener('submit', () => {
submitBtn.disabled = true;
submitBtn.textContent = 'Submitting…';
});
</script>disabled button is skipped by keyboard tab order and invisible to some assistive technology interactions. When you need a button to look disabled but still be announced/focusable (e.g. to explain why it's inactive), consider aria-disabled="true" plus your own click-blocking logic instead.The name/value Pair on Submit Buttons
A submit button can carry its own name and value, which get included
in the form data — useful when a form has multiple submit buttons that
should each trigger different behavior server-side (e.g. "Save Draft" vs
"Publish").
named-submit-buttons.html
<form method="post" action="/posts/42"> <textarea name="body"></textarea> <button type="submit" name="action" value="draft">Save Draft</button> <button type="submit" name="action" value="publish">Publish</button> </form>
Only the button that was actually clicked sends its name=value pair —
the server can branch on action to know which button the user pressed.
Styling Considerations
Buttons inherit weird default styling from the browser's user-agent stylesheet (borders, background, font) — most design systems reset it with something like
appearance: noneplus explicitborder/background/fontrules.Keep a visible
:focus-visiblestyle — never remove focus outlines without replacing them, or keyboard users lose track of where they are.Preserve a minimum touch target size (roughly 44×44px) for buttons that will be tapped on mobile.
Use real
<button>elements instead of clickable<div>s or<span>s — buttons get keyboard support (Enter/Space activation), focus, and the correct accessibility role for free.
aria-label (e.g. aria-label="Close dialog") so screen reader users know what it does.type explicitly on every button. Default to type="button" for anything that isn't meant to submit or reset a form, and reserve the implicit submit default for the one button that should actually send the form.