Skip to content

feat: add semantic click events on child components (ListItem, MenuItem, Tab, etc.) #13304

@pskelin

Description

@pskelin

Problem

Several container components fire click/press events on behalf of their children (e.g., List fires item-click, Menu fires item-click), but the child elements themselves have no public click event. This means framework consumers (React, Angular, Vue) using wrappers like createReactComponent cannot attach onClick handlers directly on child elements — they must listen on the parent and match the clicked item from the event detail.

For example, React consumers expect to write:

<ListItemStandard onClick={() => handleClick()}>Product A</ListItemStandard>

But currently must write:

<List onItemClick={(e) => { if (e.detail.item === targetRef) handleClick(); }}>
  <ListItemStandard>Product A</ListItemStandard>
</List>

Prior Art

This pattern has already been implemented for:

  • TableRow — fires own click + Table keeps row-click (#13303)
  • TableRowActionBase — fires own click + Table keeps row-action-click
  • SideNavigationSelectableItemBase — fires own click + SideNavigation keeps item-click
  • Button, Link, Icon, CardHeader, Tag, Avatar — all suppress the native click and fire a semantic CustomEvent("click") covering mouse + keyboard

The pattern: intercept the native DOM click on the child via stopImmediatePropagation, fire a CustomEvent("click") via fireDecoratorEvent, then call the parent's handler for backward compatibility.

Candidates

High impact

Child Component Parent Component Parent Event Mechanism
ListItemBase (all variants) List item-click Private _press event → List re-fires
MenuItem Menu item-click Via inner List's item-click
TreeItemBase / TreeItem Tree item-click Via inner List's item-click
NotificationListItem NotificationList item-click Private _press → inner List → parent
UserMenuItem UserMenu item-click Via inner List's item-click

Note: ListItemBase is the foundation. Adding a semantic click there would cascade to MenuItem, TreeItem, NotificationListItem, and all other ListItem variants.

Medium impact

Child Component Parent Component Parent Event Mechanism
Tab TabContainer tab-select Pure DOM delegation, no child event
BreadcrumbsItem Breadcrumbs item-click Internal Link click, parent maps to item
SegmentedButtonItem SegmentedButton selection-change Pure DOM delegation, no child event
WizardTab Wizard step-change Private selection-change-requested

Low impact

Child Component Parent Component Parent Event
ColorPaletteItem ColorPalette item-click

Implementation approach

For each candidate:

  1. Declare click in the base class eventDetails (to preserve JSX type compatibility in the hierarchy)
  2. Add @eventStrict("click", { bubbles: true }) on the concrete child class
  3. Intercept the native click in the constructor (this.addEventListener("click", ...)) — suppress via stopImmediatePropagation, fire fireDecoratorEvent("click")
  4. Keep the existing parent-level event (item-click, tab-select, etc.) for backward compatibility

Suggested order

  1. ListItemBase — highest impact, cascades to Menu, Tree, NotificationList
  2. Tab — commonly requested by framework consumers
  3. BreadcrumbsItem / SegmentedButtonItem — smaller scope, straightforward

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions