Per-component: BigCalendar

When events are domain-specific, the generic wrapper can't know what a meaningful trace looks like. A calendar has selectEvent, navigate, and viewChange -- none of these are standard XMLUI events. The wrapper provides the plumbing; the render component provides the semantics.

The plumbing: captureNativeEvents

In CalendarWrapped.tsx, the wrapper config includes:

{
  captureNativeEvents: true,
}

This tells wrapComponent to inject an onNativeEvent callback into the render component's props. The render component calls this callback whenever a library-native event fires, and the wrapper traces it automatically with a native: prefix.

The semantics: structured native events

In CalendarRender.tsx, the render component maps react-big-calendar's callbacks to onNativeEvent calls with structured fields:

onNativeEvent?.({
  type: "selectEvent",
  displayLabel: event.title || "event selected",
  title: event.title,
  start: event.start,
  end: event.end,
});
onNativeEvent?.({
  type: "navigate",
  displayLabel: dayjs(date).format("MMMM YYYY"),
  date: date.toISOString(),
});
onNativeEvent?.({
  type: "viewChange",
  displayLabel: view,
  view,
});

The displayLabel field is what appears in the inspector and in trace-tools output. "Team Standup" is more useful than "selectEvent". "March 2026" is more useful than "navigate". The wrapper doesn't need to know what a calendar event is -- the render component provides that context.

Notice that the trace also includes the aria-label from the XMLUI markup -- BigCalendar [Demo calendar]. That's Level 1's prop forwarding at work: wrapComponent forwards aria-label to the render component automatically, and the trace system picks it up as the component's accessible name. If a page had two calendars, the trace would distinguish them by label. The levels build on each other.

Demo

Interact with the calendar below -- click an event, navigate between months, switch between Month/Week/Day/Agenda views.

<App>
  <BigCalendar
    aria-label="Demo calendar"
    height="500px"
    events='{[
      {"title": "Team Standup", "start": "2026-03-10T09:00:00", "end": "2026-03-10T09:30:00"},
      {"title": "Design Review", "start": "2026-03-11T14:00:00", "end": "2026-03-11T15:00:00"},
      {"title": "Sprint Planning", "start": "2026-03-12T10:00:00", "end": "2026-03-12T11:30:00"},
      {"title": "All Hands", "start": "2026-03-15T16:00:00", "end": "2026-03-15T17:00:00"},
      {"title": "1:1 with Manager", "start": "2026-03-17T11:00:00", "end": "2026-03-17T11:30:00"},
      {"title": "Release Retro", "start": "2026-03-20T15:00:00", "end": "2026-03-20T16:00:00"}
    ]}' />
</App>
<App>
  <BigCalendar
    aria-label="Demo calendar"
    height="500px"
    events='{[
      {"title": "Team Standup", "start": "2026-03-10T09:00:00", "end": "2026-03-10T09:30:00"},
      {"title": "Design Review", "start": "2026-03-11T14:00:00", "end": "2026-03-11T15:00:00"},
      {"title": "Sprint Planning", "start": "2026-03-12T10:00:00", "end": "2026-03-12T11:30:00"},
      {"title": "All Hands", "start": "2026-03-15T16:00:00", "end": "2026-03-15T17:00:00"},
      {"title": "1:1 with Manager", "start": "2026-03-17T11:00:00", "end": "2026-03-17T11:30:00"},
      {"title": "Release Retro", "start": "2026-03-20T15:00:00", "end": "2026-03-20T16:00:00"}
    ]}' />
</App>

Before and after

Without native event capture, clicking a calendar event or navigating between months produces no trace at all. These aren't standard XMLUI events like didChange or gotFocus -- they're react-big-calendar's own callbacks (onSelectEvent, onNavigate, onView). The wrapper doesn't know they exist, so XMLUI's trace system sees nothing.

With captureNativeEvents: true and structured onNativeEvent calls, each interaction appears in the inspector with a meaningful label:

native:viewChange "week"
native:navigate "April 2026"

Those are real labels from the latest trace export. The important point is that the calendar is no longer opaque to the trace system: instead of silence, the Inspector gets domain-level events that describe what the user actually did.

The pattern

The wrapper provides the plumbing (captureNativeEvents: true injects onNativeEvent). The render component provides the semantics (structured displayLabel fields). This division of labor means:

  • The wrapper config is minimal -- one boolean flag
  • The render component is pure React -- any React developer can write it
  • New event types don't require changes to the core wrapper engine
  • The trace output is meaningful to humans and AIs without reading source code

This is the pattern for any third-party library with domain-specific events: ECharts (bar clicks with data values), Mapbox (feature clicks with coordinates), ag-Grid (cell edits with row data). The render component knows what the events mean. The wrapper knows how to trace them.