A Small HTML Habit Worth Keeping: Explicit Button Types

Abstract person on a road to a decision.

Across two recent projects, the same issue tripped me up. While building complex search forms, buttons used to show and hide groups of filters were also submitting the form when clicked.

The culprit was a missing type attribute.

It's a small omission that's easy to overlook because most of the time a button works exactly as expected. But when a <button> lives inside a <form>, browsers treat it as a submit button unless told otherwise.

That behavior is defined by the HTML specification. If a <button> element is associated with a form and no type is provided, its default behavior is submit.

Most of the time this isn't a problem. Many UI controls live outside forms, and modern JavaScript often obscures the underlying browser behavior. But once buttons start controlling accordions, tabs, filter groups, menus, or other interface elements inside a form, the default becomes important.

The Problem with Implicit Behavior

Modern interfaces often place interactive components inside forms.

A faceted search experience may include collapsible filter groups. An application form may contain tabs that organize sections of content. An advanced search interface may reveal additional options on demand.

All of these patterns are legitimate uses of the <button> element because they represent user actions. The problem occurs when the button's purpose is to manage interface state rather than submit form data.

<form>
  <button aria-expanded="false">
    Show Filters
  </button>
</form>

In this example, clicking the button will submit the form because no type has been specified.

Depending on the implementation, the issue may be obvious immediately, or it may only surface after additional functionality is added. In larger applications, the connection between a UI control and an unexpected form submission is not always immediately apparent.

Make the Intent Explicit

Any button whose purpose is to control interface behavior rather than submit form data should explicitly declare:

<button type="button">
  Show Filters
</button>

This removes ambiguity and makes the button's purpose clear to both browsers and developers.

The button now behaves consistently regardless of whether it lives inside a form today or gets moved into one later.

Just as importantly, someone reading the markup no longer has to remember the browser's default behavior to understand the component's intent.

Why This Matters on Larger Projects

On a small component, the impact is usually minor.

On larger websites and applications, components are often reused across templates, content types, and different sections of the platform. A disclosure button that originally lived outside a form may eventually be reused inside a search interface, filtering experience, or multi-step workflow.

Without an explicit type, the behavior of that component changes based on its context.

That creates a category of bugs that can be frustrating to track down because the component appears to work correctly in some places but not others.

Adding type="button" helps make components more portable and reduces the likelihood of unexpected behavior as interfaces evolve.

A Simple Rule of Thumb

When using the <button> element, declare the type explicitly.

Submit buttons should use:

<button type="submit">
  Search
</button>

Reset buttons should use:

<button type="reset">
  Reset
</button>

Buttons that control interface behavior should use:

<button type="button">
  Toggle Filters
</button>

The additional attribute is small, but it makes the purpose of the element clear and prevents a surprisingly common source of bugs.

As UI patterns become more interactive and forms become more complex, relying on implicit browser behavior becomes increasingly risky. A few extra characters in the markup can save time debugging later.

Usability

Read This Next