The <button> element represents an actionable control. Native buttons participate in focus order, respond to Space/Enter, and expose roles automatically.
Types
type="submit"(default inside forms): submits enclosing form.type="reset": restores defaults—rarely desirable UX.type="button": generic actions like toggles or dialogs.
<button type="button" aria-expanded="false">Menu</button>
Rendered output
Never fake buttons
<div onclick>lacks keyboard semantics unless you rebuild ARIA roles, tab focus, and key handlers.- Anchor tags styled as buttons confuse users expecting navigation—reserve
afor hyperlinks.
Forms integration
Outside forms, default type still behaves as browsers specify—explicit type="button" avoids accidental submissions when templates move markup.
Icons inside buttons
Include visually hidden text or aria-label when only glyphs appear—icons alone rarely suffice.
What breaks real users
- Submit buttons without explicit
type—when markup moves between forms/pages, accidental form posts ship. - Disabled buttons lacking explanatory copy nearby—tell users why and how to fix eligibility.
- Double submission: disabling button after click still needs optimistic UI + server confirmation to avoid duplicated charges.
Touch + pointer divergence
Taps don’t synthesize hover—don’t tuck critical controls behind hover-only affordances anchored to faux buttons.
Important interview questions and answers
- Q: What is the practical difference between `id` and `class`?
A: `id` must be unique and is used for fragments/labeling; `class` is reusable for styling and behavior grouping. - Q: Why is `defer` commonly preferred for scripts?
A: It preserves HTML parsing, executes after parse, and avoids blocking rendering unlike classic synchronous scripts. - Q: How do `srcset` and `sizes` work together?
A: `srcset` provides candidate files and `sizes` tells expected rendered width so the browser can pick an optimal resource.
Pitfall: Use <button type="button"> inside forms unless submitting.