RRenDSv0.13.0

Foundations

Events

Every interactive RenDS component dispatches its own CustomEvents. This page is the single source of truth: 38 event names across 51 component-event contracts, their detail shape, and bubbling behavior. Use it to integrate RenDS with your application state, analytics, or another framework.

Convention

Naming

All RenDS custom events follow the prefix ren-. Most are namespaced by component (ren-tab-change, ren-slide-change, ren-files-added); a handful of generic names are reused across components. Their exact flags and payload remain component-specific, so use the catalog below as the contract:

  • ren-open / ren-close — fired by several overlay-style components. Some close events include { returnValue }.
  • ren-change — fired when a control's value changes. Its payload reflects that control's value model.

If you need to disambiguate between e.g. a Dialog opening and a Combobox opening on the same page, scope your listener to the host element rather than to document.

Defaults

Bubbles, composed, cancelable

  • bubbles: true on virtually every event. RenDS components live in light DOM, so events bubble naturally — listen anywhere up the tree.
  • composed varies by component. RenDS uses light DOM, so this flag mainly records whether the event is intended to cross a future host boundary.
  • cancelable: false by default. ren-submit is the documented exception; listeners may mark it prevented, while asynchronous work is coordinated through detail.waitUntil().

Listen on the host, not document — usually

For component-specific logic, listen on the component element (combo.addEventListener(…)). For cross-cutting concerns like analytics, listening on document with delegation is fine — every event bubbles by default.

Reference

Event catalog

38 event names across 51 component-event contracts and 26 components. means the field is not explicitly set (uses the CustomEvent default, which is false).

Component Event bubbles composed cancelable detail
ren-accordionren-accordion-changetrue{ item, isOpen, index }
ren-calendarren-date-selecttruetrue{ date, range, dates }
ren-carouselren-slide-changetruetrue{ index, total, id }
ren-color-pickerren-inputtruetrue{ hex, rgb, hsl, alpha }
ren-color-pickerren-changetruetrue{ hex, rgb, hsl, alpha }
ren-comboboxren-searchtrue{ query }
ren-comboboxren-changetrue{ value, item }
ren-comboboxren-opentrue
ren-comboboxren-closetrue
ren-context-menuren-context-menu-opentruetrue{ x, y, target }
ren-date-pickerren-date-picker-opentruetrue
ren-date-pickerren-date-picker-closetruetrue
ren-date-pickerren-changetruetrue{ value, formattedValue }
ren-date-range-pickerren-date-range-opentruetrue
ren-date-range-pickerren-date-range-closetruetrue
ren-date-range-pickerren-changetruetrue{ value, formattedValue, preset, days }
ren-dialogren-opentruetrue
ren-dialogren-closetruetrue{ returnValue }
ren-dropzoneren-files-addedtrue{ files }
ren-hover-cardren-hover-card-opentruetrue
ren-hover-cardren-hover-card-closetruetrue
ren-menuren-menu-selecttrue{ item, value }
ren-menuren-menu-opentrue
ren-menuren-menu-closetrue
ren-number-fieldren-changetruetrue{ value, oldValue }
ren-otpren-changetruetrue{ value }
ren-otpren-completetruetrue{ value }
ren-popoverren-opentrue
ren-popoverren-closetrue
ren-selectren-select-opentrue
ren-selectren-select-closetrue
ren-selectren-select-changetrue{ value, label, item }
ren-sheetren-opentrue
ren-sheetren-closetruetrue{ returnValue }
ren-sliderren-slider-inputtruetrue{ value }
ren-sliderren-slider-changetruetrue{ value }
ren-tabsren-tab-changetruetrue{ tab, panel, index, id }
ren-toggle-groupren-toggle-changetruetrue{ value, items }
ren-tooltipren-opentrue
ren-tooltipren-closetrue
ren-commandren-command-selecttruetrue{ item, value, action }
ren-formren-submit-errortruetrue{ error }
ren-formren-invalidtruetrue{ errors }
ren-formren-submittruetruetrue{ values, form, waitUntil }
ren-formren-field-validatedtruetrue{ name, valid, error }
ren-formren-step-changetruetrue{ step, totalSteps }
ren-menubarren-menubar-selecttruetrue{ item, value, checked }
ren-sidebarren-sidebar-toggletruetrue{ collapsed }
ren-tableren-sorttruetrue{ column, direction }
ren-tableren-selecttruetrue{ selected }
ren-tableren-filtertruetrue{ value }

Patterns

How to listen

Targeted listening (preferred)

Listen on the specific component instance. Best for component-specific logic.

const combo = document.querySelector('ren-combobox[name="country"]');

combo.addEventListener('ren-change', (e) => {
  console.log(e.detail.value, e.detail.item);
});

Global delegation

Listen on document and filter by target. Best for cross-cutting concerns (analytics, undo stack, audit log).

document.addEventListener('ren-tab-change', (e) => {
  analytics.track('tab_changed', {
    component: e.target.id,
    tab: e.detail.tabId,
  });
});

Filtering by detail

table.addEventListener('ren-select', (e) => {
  if (e.detail.selected.length === 0) {
    bulkBar.hidden = true;
  } else {
    bulkBar.hidden = false;
    bulkBar.querySelector('.count').textContent = e.detail.selected.length;
  }
});

One-shot listening

Use the standard { once: true } option — RenDS events are plain CustomEvents.

dialog.addEventListener('ren-close', () => {
  cleanup();
}, { once: true });

Watch out

Common gotchas

  • Don't preventDefault() to veto state changes. RenDS events fire after the change applies; cancellation is not wired. To veto, intercept the user action upstream (e.g., disable the trigger button until your check passes).
  • Two components, same event. If a Combobox and a Select are on the same page, both dispatch ren-change with similar detail. Use e.target.tagName or scope your listener.
  • Cross-component ren-open / ren-close. Dialog, Sheet, Combobox, Hover Card all fire these. Same trick: scope to host or check e.target.tagName.
  • Form events fire on the <ren-form> host, not on <form>. Listen on the custom element, not the inner form element.