Widget Components Reference
Detailed reference for each Checkout Widget component — lifecycle, states, error handling, styling, and co-branding.
This page provides the detailed technical reference for each of the three Checkout Widget components. For architecture context and the system diagram, see the Widget Overview.
weatherit-widget — Protection Selector
The main component. Manages the full lifecycle from data input through quoting to protection selection.
Mount Lifecycle
flowchart TB
A["connectedCallback()"] --> B{"Attributes present?<br/>(lat, start, etc.)"}
B -->|Yes| C["Use attribute values"]
B -->|No| D["Listen for RoomStay<br/>checkoutView event"]
D --> C
C --> E["Fetch partner branding<br/>GET /partners/:id"]
E -->|Success| F["Apply partner colour +<br/>store logo URL"]
E -->|Failure| G["Use default WeatherIt<br/>branding, continue"]
F --> H["Fetch quote<br/>POST /quotes?partner_id=xxx"]
G --> H
H --> I["Render protection cards<br/>(Full / Budget)"]
I --> J["Auto-select Full Protection"]
J --> K["Fire weatherit:coverage-selected"]
style A fill:#e8f4f8
style K fill:#e8f5e9
User Interactions
| Action | Result |
|---|---|
| Select Full / Budget (first time) | Fires weatherit:coverage-selected |
| Switch between Full / Budget | Fires weatherit:coverage-changed with new option data |
| Select "No Protection" | Fires weatherit:coverage-declined. Widget stays visible. Customer can re-select at any time. |
| Click "Learn more" | Opens modal with protection details, weather station info, and trigger information |
Internal State
interface WidgetState {
loading: boolean;
error: string | null;
quoteData: Quote | null;
selectedOption: PricingOption | null; // null when "No Protection" selected
partnerBranding: Partner | null;
learnMoreOpen: boolean;
declined: boolean; // true when customer selects "No Protection"
}Error Handling
| Error | Behaviour |
|---|---|
| API unreachable | Widget hides — checkout continues unaffected |
| Quote unavailable (location not covered) | Widget hides |
| Partner not found | Uses default WeatherIt branding, continues quoting |
| Invalid attributes (missing required) | Widget hides, fires weatherit:widget-error event |
In all error cases, the partner's checkout flow is unaffected. The widget is designed to fail silently rather than block checkout.
weatherit-cart-item — Cart Line Item
A passive component. No API calls. Listens for Custom Events from weatherit-widget.
Behaviour
flowchart LR
A["Mount:<br/>hidden by default"] --> B{"Event received?"}
B -->|"coverage-selected /<br/>coverage-changed"| C["Show line item:<br/>Rain Protection — tier — $premium"]
B -->|"coverage-declined"| D["Hide"]
C --> B
D --> B
When visible, the line item displays:
- Title:
Rain Protection — {optionName} - Amount:
${premium} - Subtitle: "Charged securely by WeatherIt"
Internal State
interface CartItemState {
visible: boolean;
optionName: string;
premium: number;
}weatherit-confirmation — Confirmation Page
A standalone component on the booking confirmation page. No shared state with the checkout widgets — it operates independently on a different URL.
Mount Lifecycle
flowchart TB
A["connectedCallback()"] --> B["Fetch partner branding<br/>GET /partners/:id"]
B --> C{"policy-id<br/>attribute set?"}
C -->|Yes| D{"hide-on-confirmed<br/>attribute set?"}
D -->|Yes| E["Hide component"]
D -->|No| F["Show: Rain Protection<br/>confirmed summary"]
C -->|No| G{"quote-id<br/>attribute set?"}
G -->|Yes| H["Show: Upsell card<br/>with premium + 'Add now' link"]
G -->|No| I["Show: Generic offer<br/>'Protect your stay' + link"]
style F fill:#e8f5e9
style H fill:#fff3e0
style I fill:#e8f4f8
style E fill:#f5f5f5
Display States
| State | Condition | Widget Shows |
|---|---|---|
| Policy confirmed | policy-id attribute set | "Rain Protection confirmed" summary — or hides if hide-on-confirmed is set |
| Upsell | quote-id attribute set (no policy-id) | Upsell card with the quote's premium and "Add now" link to QLP |
| Generic offer | Neither policy-id nor quote-id set | "Protect your stay from rain" message with link to QLP |
Upsell and generic offer links:
https://qlp.weatherit.ai/?partner={partnerId}&booking={bookingRef}
With a quote:
https://qlp.weatherit.ai/?quote_id={quoteId}&partner={partnerId}&booking={bookingRef}
The customer completes the purchase on WeatherIt's hosted page.
Internal State
interface ConfirmationState {
loading: boolean;
policyData: Policy | null;
quoteData: Quote | null;
partnerBranding: Partner | null;
}Styling & Co-Branding
All components use Shadow DOM. Styles are fully scoped — zero leakage in either direction between the widget and the partner's page.
Partner Branding
Partner branding is fetched from GET /partners/:id and applied automatically:
- Primary colour — set as
--partner-primary-colorCSS custom property - Logo — displayed in the "Powered by WeatherIt" lockup
CSS Custom Properties
Partner-controlled:
--partner-primary-color: #005a8b; /* fetched from partner config, fallback: Trust Blue */
--partner-primary-light: color-mix(in srgb, var(--partner-primary-color) 8%, white);
--partner-primary-dark: color-mix(in srgb, var(--partner-primary-color), black 20%);WeatherIt design tokens:
--wit-success: #28A745;
--wit-error: #DC3545;
--wit-warning: #FFC107;
--wit-text: #1a1a1a;
--wit-text-secondary: #8B95A1;
--wit-border: #e5e7eb;
--wit-radius: 8px;
--wit-radius-lg: 12px;
--wit-font: 'Inter', 'Open Sans', 'Montserrat', system-ui, sans-serif;"Powered by WeatherIt" Lockup
Appears at the bottom of weatherit-widget:
- Partner logo (from
partner.logo_url) alongside WeatherIt logo - Partner logo minimum 50% of WeatherIt logo size
- 2x clear space between logos
- Text: "Powered by WeatherIt"
Responsive Breakpoints
| Breakpoint | Width | Layout |
|---|---|---|
| Mobile | 320-767px | Single column, stacked cards |
| Tablet | 768-1023px | Side-by-side protection cards |
| Desktop | 1024px+ | Full layout |
Accessibility
- Touch targets: 44x44px minimum
- Input height: 48px minimum
- Minimum contrast ratio: 4.5:1 (WCAG 2.1 AA)
Visual placeholder — Visuals showing each component in its various states will be added here.
Updated 7 months ago
