Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Drop-ins overview

Events

Drop-in components implement an event-driven architecture that uses the @dropins/tools/event-bus.js module to facilitate communication between components. This event system enables drop-ins to respond to application state changes, maintain loose coupling between components, and keep their state synchronized across your storefront.

Event system architecture

The system uses a publish-subscribe pattern where components can:

  1. Subscribe to specific events using events.on()
  2. Emit events using events.emit()
  3. Unsubscribe using subscription.off()

This pattern allows drop-ins to communicate without having direct dependencies on each other, making your storefront more modular and maintainable.

Loading diagram...
Drop-ins communicate through the central event bus without direct dependencies on each other. Custom storefront code (pink) can also emit events like locale and authenticated that drop-ins listen to.

Common event patterns

Drop-ins use consistent naming conventions for their events:

  • dropin/initialized: Fires when a drop-in completes initialization
  • dropin/updated: Fires when a drop-in’s state changes
  • dropin/data: Provides the current data state
  • dropin/reset: Fires when a drop-in’s state is reset
  • dropin/error: Fires when an error occurs

Event directions

Events can flow in different directions:

  • Emits: The drop-in publishes this event for others to consume
  • Listens: The drop-in subscribes to this event from external sources
  • Emits and listens: The drop-in both publishes and subscribes to this event (bidirectional)
Loading diagram...
Three types of event flow: emits only (blue), listens only (indigo), and bidirectional (purple).

Event subscription

Components subscribe to events to listen for and respond to the changes elsewhere in the application.

Subscription syntax

To subscribe to an event, provide:

  1. The event name (as a string)
  2. An event handler callback function that receives the payload
  3. Optional configuration parameters
const subscription = events.on('event-name', handler, options);

Subscription options

Event subscriptions support an optional configuration parameter:

  • eager: true: The handler executes immediately if the event has been emitted previously
  • eager: false (default): The handler only responds to future emissions of the event

See Best Practices for detailed guidance on using eager mode effectively.

Example: Subscribing to an event

Listen to an initialization event:

import { events } from '@dropins/tools/event-bus.js';
// Subscribe to the event
const subscription = events.on('cart/initialized', (data) => {
console.log('Cart initialized with data:', data);
// Handle the cart data
updateUI(data);
});
// Later, unsubscribe when no longer needed
subscription.off();

Event emission

Components emit events to share information with other components, drop-ins, or external systems.

Emission syntax

To emit an event, provide:

  1. The event name (as a string)
  2. The payload containing the data to share
events.emit('event-name', payload);

Example: Emitting an event

Emit an event when state changes:

import { events } from '@dropins/tools/event-bus.js';
function updateCartQuantity(itemId, quantity) {
// Update the cart
const updatedCart = performCartUpdate(itemId, quantity);
// Notify other components about the change
events.emit('cart/updated', updatedCart);
}

Common events reference

Drop-ins use common events for cross-component communication, authentication management, localization, and error handling.

EventCategoryUsed ByDescription
authenticatedAuthenticationMost B2C & B2B drop-insAuthentication state changes
errorError HandlingMost drop-insError notifications
localeLocalizationAll drop-insLanguage/locale changes

Best practices

Use type-safe event names

Import event types when available to ensure you’re using the correct event names:

import type { Events } from '@adobe-commerce/event-bus';
// TypeScript will validate the event name
events.on('cart/initialized', (data) => {
// ...
});

Use eager mode wisely

Set eager: true when you need the current state immediately:

// Good: Getting initial state on component mount
events.on('cart/data', (data) => {
initializeComponent(data);
}, { eager: true });
// Good: Only responding to future changes
events.on('cart/updated', (data) => {
updateComponent(data);
}, { eager: false });

Keep handlers focused

Event handlers should be small and focused on a single responsibility:

// Good: Focused handler
events.on('cart/updated', (cart) => {
updateCartBadge(cart.itemCount);
});
// Avoid: Handler doing too much
events.on('cart/updated', (cart) => {
updateCartBadge(cart.itemCount);
updateMiniCart(cart);
recalculateTotals(cart);
logAnalytics(cart);
// Too many responsibilities
});

Use state management helpers

Use events.lastPayload('<event>') to retrieve the most recent state without waiting for the next event:

// Get current authentication state
const isAuthenticated = events.lastPayload('authenticated');
if (isAuthenticated) {
console.log('User is authenticated');
}
// Get current locale
const currentLocale = events.lastPayload('locale');
console.log('Current locale:', currentLocale);

Handle errors gracefully

Always include error listeners in production applications to gracefully handle failures and provide helpful feedback to users.


Event sources: External vs. Internal

Events can originate from different sources in your storefront:

External events are fired by:

  • Your storefront application code (authentication, locale changes)
  • Other drop-ins (cart updates affecting checkout)
  • Third-party integrations (payment processors, analytics)

Internal events are fired by:

  • Components within the same drop-in (checkout steps communicating with each other)
  • Drop-in initialization and state management

Understanding whether an event is external or internal helps you determine:

  • Where to emit the event in your custom code
  • Which events you need to handle from your storefront
  • How drop-ins coordinate internally vs. with the broader application

The following diagram illustrates this using the Checkout drop-in as an example:

Loading diagram...
External events (thin dashed arrows) flow from outside sources through the Event Bus to the drop-in. Internal events (thick solid arrows) coordinate between containers within the same drop-in.

The Checkout drop-in:

  • Listens to external events: authenticated, cart/initialized, cart/updated, cart/merged, cart/reset, cart/data, locale
  • Uses internal events: checkout/initialized, checkout/updated, shipping/estimate (for coordinating between its own containers)

Event declaration

Events are strongly typed using TypeScript declaration merging to provide type safety and autocomplete support. Each drop-in declares its events by extending the Events interface from the event bus.

Basic declaration

Here’s a simplified example of how events are declared:

declare module '@adobe-commerce/event-bus' {
interface Events {
'dropin/initialized': DataModel | null;
'dropin/updated': DataModel | null;
'dropin/data': DataModel;
authenticated: boolean;
locale: string;
error: { source: string; type: string; error: Error };
}
}

Complete declaration example

In practice, drop-ins declare their events with imports and type extensions. Here’s a more comprehensive example from the Checkout drop-in:

import {
Cart as CheckoutData,
ShippingEstimate,
ValuesModel,
} from '@/checkout/data/models';
import { CartModel } from '@/checkout/types/cart';
declare module '@adobe-commerce/event-bus' {
interface Events {
'cart/initialized': CartModel | null;
'cart/updated': CartModel | null;
'cart/reset': void;
'cart/merged': { oldCartItems: any[] };
'checkout/initialized': CheckoutData | null;
'checkout/updated': CheckoutData | null;
'checkout/values': ValuesModel;
'shipping/estimate': ShippingEstimate;
authenticated: boolean;
error: { source: string; type: string; error: Error };
}
interface Cart extends CartModel {}
}

This pattern allows TypeScript to provide autocomplete and type checking for both event names and their payloads throughout your application.


Next steps

  • Review the Common events reference for detailed documentation on shared events
  • Review the Event Bus API Reference for detailed API methods and code examples
  • Check individual drop-in event pages for component-specific events
  • Try drop-in tutorials for practical event usage examples