Events
@alviere/ui components communicate through Custom Events dispatched on the host element. This page is the canonical reference for all event names, payload shapes, and dispatch behaviour.
Event dispatch model
All form, flow, and input component events are dispatched with:
new CustomEvent(name, {
detail: payload,
bubbles: true,
composed: true,
})
bubbles: true means events propagate up through the DOM tree. composed: true means they cross shadow DOM boundaries — events dispatched inside a Web Component's shadow root reach listeners on the host element and beyond. This is what allows MultiStepFlow to surface domain events from its child steps without any manual forwarding.
Element component events (Checkbox, ListItem, Modal) use Svelte's event dispatcher and may not be composed by default — do not rely on them crossing shadow DOM boundaries.
Quick reference
Form and flow events
| Component | Events dispatched |
|---|---|
CreateAccount / CreateConsumerAccount / CreateBusinessAccount |
account, form-success, form-error, form-barrier, form-action-required |
AddBankAccount |
payment-method, form-success |
StartOnboarding |
form-success, form-error, form-barrier |
CheckoutConfirm |
form-success |
MultiStepFlow |
flow-step-complete, flow-step-error, flow-complete, flow-reset + bubbles child events |
Input events
| Component | Events dispatched |
|---|---|
TextInput, CurrencyInput, DateOfBirthInput, EinInput |
text-input, text-change, text-focus, text-blur |
PhoneInput |
phone-input, phone-change, phone-focus, phone-blur |
SearchSelect |
search-select-change, search-select-input, search-select-open, search-select-close |
FileUpload |
(none) |
Element events
| Component | Events dispatched |
|---|---|
Checkbox |
change |
ListItem |
select |
Modal |
close |
LegalTextConsent |
legal-texts-change, view |
Payload interfaces
All interfaces below are exported from @alviere/ui.
BaseComponentEventDetail
Foundation for all input events.
interface BaseComponentEventDetail {
value: string;
rawValue: string;
isValid: boolean;
validationState: ValidationState;
errorMessage?: string;
hasInteracted: boolean;
}
InputEventDetail
Dispatched by TextInput, CurrencyInput, DateOfBirthInput, EinInput.
interface InputEventDetail extends BaseComponentEventDetail {
characterCount?: number;
maxLength?: number;
}
PhoneInputEventDetail
Dispatched by PhoneInput.
interface PhoneInputEventDetail extends BaseComponentEventDetail {
formattedValue: string;
countryCode?: string;
}
SearchSelectEventDetail
Dispatched by SearchSelect.
interface SearchSelectEventDetail extends BaseComponentEventDetail {
selectedOption: any; // full option object { value, label }
options: any[];
searchQuery?: string;
}
AccountEventDetail
Dispatched as the account domain event by CreateAccount and its variants.
interface AccountEventDetail {
account_uuid: string;
status: string;
account_status: string; // mirrors status
skipped?: true; // present when the account already existed and was skipped
}
PaymentMethodEventDetail
Dispatched as the payment-method domain event by AddBankAccount.
interface PaymentMethodEventDetail {
payment_method_uuid: string;
status: string;
}
StepEventDetail
Dispatched by MultiStepFlow on flow-step-complete and flow-step-error.
interface StepEventDetail {
stepIndex: number;
stepType: string;
result: any; // accumulated results from all steps up to this point
error?: Error;
}
StepBarrierEventDetail
Dispatched as form-barrier by form components.
interface StepBarrierEventDetail {
stepType: string;
stepIndex?: number;
account_uuid?: string;
status?: string;
title?: string;
message?: string;
description?: string;
}
StepActionRequiredEventDetail
Dispatched as form-action-required by CreateAccount.
interface StepActionRequiredEventDetail {
stepType: string;
stepIndex?: number;
account_uuid?: string;
status?: string;
status_reason?: string;
message?: string;
}
FlowEventDetail
Dispatched by MultiStepFlow on flow-complete and flow-reset.
interface FlowEventDetail {
currentStep: number;
totalSteps: number;
stepResults: Record<number, any>;
isComplete: boolean;
}
Event flows
Standalone form
user interaction
→ component logic + API call
→ domain event (account / payment-method) ← optional
→ form-success / form-error / form-barrier / form-action-required
MultiStepFlow
step emits form-success
→ MultiStepFlow stores result, merges account_uuid / payment_method_uuid
→ MultiStepFlow emits flow-step-complete
→ next step receives merged data automatically
...
final step completes
→ MultiStepFlow emits flow-complete
Domain events (account, payment-method) from child steps bubble through the flow element automatically — no forwarding needed. Listen for them on alviere-multi-step-flow directly.
Component events
CreateAccount / CreateConsumerAccount / CreateBusinessAccount
| Event | When | Key payload fields |
|---|---|---|
account |
Account created or confirmed | account_uuid, status, account_status, skipped? |
form-success |
Step completed | account_uuid, status, success: true, skipped?, action_required? |
form-error |
Critical failure | error, stepType |
form-barrier |
Account in manual review | account_uuid, status, title, message, description? |
form-action-required |
Account needs additional fields | account_uuid, status, status_reason, message |
form-success is also dispatched in action-required mode (with action_required: true) when the account exists but needs field updates.
AddBankAccount
| Event | When | Key payload fields |
|---|---|---|
payment-method |
Bank account linked | payment_method_uuid, status |
form-success |
User confirms selection | payment_method_uuid, payment_method_last4, payment_method_status, success: true |
form-error is not dispatched for submission failures — errors are shown inline. It fires only for critical authentication failures.
StartOnboarding
| Event | When | Key payload fields |
|---|---|---|
form-success |
Onboarding submitted (or auto-skipped) | account_uuid, status, success: true, accepted_legal_documents? |
form-error |
Onboarding failed | error, success: false |
form-barrier |
Account in manual review | account_uuid, status, title, message |
accepted_legal_documents is an array of legal text UUIDs. Present only when legal texts were configured and accepted.
CheckoutConfirm
| Event | When | Key payload fields |
|---|---|---|
form-success |
User confirms payment | amount, success: true, accepted_legal_documents? |
CheckoutConfirm makes no API calls and dispatches no error or barrier events.
MultiStepFlow
| Event | When |
|---|---|
flow-step-complete |
A step finished successfully — StepEventDetail |
flow-step-error |
A step failed — StepEventDetail with error |
flow-complete |
All steps finished — FlowEventDetail |
flow-reset |
Flow was reset — FlowEventDetail |
Child step events (account, payment-method, form-success, etc.) bubble through the flow element automatically.
Input component events
Text-style inputs
TextInput, CurrencyInput, DateOfBirthInput, EinInput all dispatch InputEventDetail:
| Event | Trigger |
|---|---|
text-input |
Every keystroke |
text-change |
Value committed (blur or enter) |
text-focus |
Field focused |
text-blur |
Field blurred |
PhoneInput
Dispatches PhoneInputEventDetail (phone-input, phone-change, phone-focus, phone-blur).
value is the E.164 normalised string (e.g. "+14155552671"). rawValue is digits only, no + prefix.
SearchSelect
Dispatches SearchSelectEventDetail:
| Event | Trigger |
|---|---|
search-select-change |
Option selected or cleared |
search-select-input |
Search query changed |
search-select-open |
Dropdown opened |
search-select-close |
Dropdown closed |
Also dispatches a legacy change event on selection for backward compatibility.
FileUpload
Dispatches no events. Read the selected file via bind:value.
Element component events
Checkbox
Event: change
{
checked: boolean;
value: any; // the component's value prop
name: string;
}
ListItem
Event: select — fires when a selectable item is clicked.
{ value: any } // from the selectable prop
Modal
Event: close — fires whenever the modal closes.
{ reason: 'backdrop' | 'escape' | 'button' | 'programmatic' }
LegalTextConsent
| Event | Payload |
|---|---|
legal-texts-change |
{ accepted: Record<string, boolean>; allAccepted: boolean; acceptedLegalTextUuids: string[] } |
view |
{ document: LegalTextDocumentConfig; legalText: LegalText } |
ComponentEvents constants
Import event name strings directly to avoid typos:
import { ComponentEvents } from '@alviere/ui';
element.addEventListener(ComponentEvents.FORM_SUCCESS, handler);
element.addEventListener(ComponentEvents.ACCOUNT, handler);
export const ComponentEvents = {
// Text inputs
TEXT_INPUT: 'text-input',
TEXT_CHANGE: 'text-change',
TEXT_FOCUS: 'text-focus',
TEXT_BLUR: 'text-blur',
// Phone input
PHONE_INPUT: 'phone-input',
PHONE_CHANGE: 'phone-change',
PHONE_FOCUS: 'phone-focus',
PHONE_BLUR: 'phone-blur',
// Search select
SEARCH_SELECT_INPUT: 'search-select-input',
SEARCH_SELECT_CHANGE: 'search-select-change',
SEARCH_SELECT_OPEN: 'search-select-open',
SEARCH_SELECT_CLOSE: 'search-select-close',
// Form lifecycle
FORM_SUCCESS: 'form-success',
FORM_ERROR: 'form-error',
FORM_BARRIER: 'form-barrier',
FORM_ACTION_REQUIRED: 'form-action-required',
FORM_SUBMIT: 'form-submit',
FORM_RESET: 'form-reset',
// Flow lifecycle
FLOW_STEP_COMPLETE: 'flow-step-complete',
FLOW_STEP_ERROR: 'flow-step-error',
FLOW_COMPLETE: 'flow-complete',
FLOW_RESET: 'flow-reset',
// Domain events
ACCOUNT: 'account',
PAYMENT_METHOD: 'payment-method',
// Legacy card inputs
CARD_PAN_INPUT: 'card-pan-input',
CARD_PAN_CHANGE: 'card-pan-change',
CARD_PAN_FOCUS: 'card-pan-focus',
CARD_PAN_BLUR: 'card-pan-blur',
CARD_CVV_INPUT: 'card-cvv-input',
CARD_CVV_CHANGE: 'card-cvv-change',
CARD_CVV_FOCUS: 'card-cvv-focus',
CARD_CVV_BLUR: 'card-cvv-blur',
CARD_EXP_INPUT: 'card-exp-input',
CARD_EXP_CHANGE: 'card-exp-change',
CARD_EXP_FOCUS: 'card-exp-focus',
CARD_EXP_BLUR: 'card-exp-blur',
} as const;
FORM_SUBMIT and FORM_RESET are defined as constants but are not currently dispatched by any component — they are reserved for future use.
Usage examples
Standalone form (Web Component)
<alviere-create-account
jwt="your-jwt-token"
business-uuid="your-business-uuid"
public-certificate="your-cert"
public-certificate-id="your-cert-id"
></alviere-create-account>
<script>
const el = document.querySelector('alviere-create-account');
el.addEventListener('account', e => {
console.log('Account created:', e.detail.account_uuid);
});
el.addEventListener('form-success', e => {
console.log('Step done:', e.detail);
});
el.addEventListener('form-barrier', e => {
showBarrierUI(e.detail.title, e.detail.message);
});
el.addEventListener('form-action-required', e => {
console.log('Additional fields required:', e.detail.status_reason);
});
el.addEventListener('form-error', e => {
console.error('Error:', e.detail.error);
});
</script>
MultiStepFlow (Web Component)
<alviere-multi-step-flow
jwt="your-jwt-token"
business-uuid="your-business-uuid"
config='{"steps":[{"type":"CREATE_ACCOUNT","label":"Account"},{"type":"ADD_BANK_ACCOUNT","label":"Bank"}]}'
></alviere-multi-step-flow>
<script>
const flow = document.querySelector('alviere-multi-step-flow');
// Flow lifecycle
flow.addEventListener('flow-step-complete', e => {
console.log('Step', e.detail.stepType, 'done. Result:', e.detail.result);
});
flow.addEventListener('flow-complete', e => {
console.log('All steps done:', e.detail.stepResults);
});
flow.addEventListener('flow-step-error', e => {
console.error('Step failed:', e.detail.stepType, e.detail.error);
});
// Domain events bubble up from child steps
flow.addEventListener('account', e => {
console.log('Account:', e.detail.account_uuid);
});
flow.addEventListener('payment-method', e => {
console.log('Payment method:', e.detail.payment_method_uuid);
});
</script>
TypeScript
import {
ComponentEvents,
type AccountEventDetail,
type PaymentMethodEventDetail,
type StepEventDetail,
type FlowEventDetail,
} from '@alviere/ui';
const flow = document.querySelector('alviere-multi-step-flow')!;
flow.addEventListener(
ComponentEvents.ACCOUNT,
((e: CustomEvent<AccountEventDetail>) => {
const { account_uuid, status } = e.detail;
console.log(account_uuid, status);
}) as EventListener
);
flow.addEventListener(
ComponentEvents.FLOW_COMPLETE,
((e: CustomEvent<FlowEventDetail>) => {
console.log('Steps:', e.detail.totalSteps, 'Results:', e.detail.stepResults);
}) as EventListener
);
Best practices
- Prefer domain events for business state. Listen for
accountandpayment-methodto capture UUIDs — these fire beforeform-successand carry the raw API data. - Always handle
form-errorandflow-step-error. Unhandled errors leave users with no feedback path. - Handle
form-barrierandform-action-requiredexplicitly when your onboarding policy may put accounts into manual review. Silently ignoring them blocks users with no UI feedback. - Use
ComponentEventsconstants in TypeScript code rather than raw strings to catch renames at compile time. - Clean up listeners on unmount in SPA frameworks — Web Components don't clean up event listeners automatically.
- Don't assume
form-successmeans API completion forCheckoutConfirm— it makes no API calls. The payload contains the confirmed amount; your code submits the payment.

