The Hidden Complexity of Custom UI: Why You Should Use Semantic HTML Buttons

The Hidden Complexity of Custom UI: Why You Should Use Semantic HTML Buttons

Recreating a native HTML button from scratch is a Sisyphean task because a simple <button> element encapsulates decades of accessibility standards, browser behaviors, and operating system integrations. To replicate a native button using a custom element, a developer must manually implement everything from keyboard focus and ARIA roles to complex form validation and submission logic.

The Requirements of a Native Button

To truly replace a native button, a custom component must satisfy a rigorous set of UX "laws" and accessibility requirements. According to MDN, the W3C ARIA specifications, and WCAG 2.2, a functional button must:

  • Role and Labeling: Possess a button role and a clear accessible label (WCAG SC 4.1.2, 1.3.1).
  • Focus Management: Be keyboard focusable and visible when focused (WCAG SC 2.4.3, 2.4.7).
  • Input Modalities: Activate via mouse click, touch, stylus, and other pointing devices.
  • Keyboard Interaction: Activate specifically on the Space and Enter keys when focused (WCAG SC 2.1.1).
  • Form Integration: Support types (submit, reset, button), participate in form validation, and handle attributes like formaction, formmethod, and formtarget (WCAG SC 3.3.1).
  • State Management: Support states such as disabled (WCAG SC 4.1.2).
  • Modern API Support: Integrate with newer browser features like the Popover API or Invoker Commands API.

The Implementation Gap: From Markup to 500 Lines of Code

Building a button from scratch reveals the massive gap between a simple HTML tag and the underlying logic required to make it work for all users.

1. Accessibility and Focus

A custom tag (e.g., <sagan-button>) is treated as a <span> by default. To make it a button, developers must manually add role="button" and tabindex="0" to ensure it appears in the accessibility tree and the page's tab order. For icon buttons, additional work is required to hide decorative emojis or icons using aria-hidden="true" and provide a descriptive aria-label to avoid screen readers announcing the literal name of an emoji.

2. Event Handling and Modalities

Native buttons handle various input methods automatically. A custom implementation must explicitly listen for mouseup, touchend, and onpointerup to cover mouse, touch, and stylus interactions. Furthermore, keyboard accessibility requires separate logic for keydown (Enter key) and keyup (Space key) to match native browser expectations.

3. Form Association and Validation

One of the most complex aspects of a native button is its relationship with HTML forms. To replicate this, a custom element must set static formAssociated = true and implement a massive array of getters and setters for attributes including type, form, formaction, formmethod, formenctype, formnovalidate, formtarget, name, and value.

It must also integrate with the Validation API, implementing methods like checkValidity() and reportValidity() and managing the validity state via ElementInternals.

4. State and Event Order

To prevent a custom button from behaving erratically, developers must wrap the addEventListener method. This ensures that internal logic (like setting an "active" state or checking if the button is disabled) runs in the correct order relative to user-defined event listeners. Without this, calling preventDefault() on a click event might not stop the button's default action if the internal handler is registered incorrectly.

Synthesis of Expert Insights

Discussion among developers highlights that the drive toward custom components often prioritizes aesthetics over usability and accessibility.

  • Usability vs. Aesthetics: Some argue that the industry has traded functional, high-contrast native widgets for "flat nonsense" that is often slower to use and less intuitive.
  • The "Accessibility Racket": There are reports of companies being sued for accessibility non-compliance, only to be "saved" by consultants who simply remove complex ARIA tags and revert the site to standard semantic HTML.
  • The Role of AI: While some suggest that AI can now generate the necessary boilerplate for custom components in minutes, others warn that AI is often trained on inaccessible code, potentially propagating poor accessibility patterns at scale.
  • Missing Native Elements: A common counter-argument is that custom components are sometimes necessary because native HTML lacks certain complex elements, such as a combobox with server-side filtering.

Conclusion: The Case for Semantic HTML

Recreating a button from scratch requires nearly 500 lines of JavaScript to achieve only a fraction of the functionality provided by a single <button> tag. The maintenance burden, the risk of legal action due to accessibility failures, and the degradation of user experience make custom-built basic UI elements an inefficient choice. Unless a specific native element does not exist for a required pattern, semantic HTML remains the gold standard for web development.

Sources