@liquidcommerce/elements-sdk 2.7.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +83 -2750
  2. package/dist/index.checkout.esm.js +6898 -6837
  3. package/dist/index.esm.js +11463 -10993
  4. package/dist/types/auto-initialize/shared-utils.d.ts +5 -0
  5. package/dist/types/constants/core.constant.d.ts +0 -4
  6. package/dist/types/core/base-component.service.d.ts +2 -1
  7. package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +1 -0
  8. package/dist/types/enums/core.enum.d.ts +11 -0
  9. package/dist/types/interfaces/configs/product-list.interface.d.ts +2 -2
  10. package/dist/types/interfaces/core.interface.d.ts +5 -4
  11. package/dist/types/modules/address/address-input.component.d.ts +11 -0
  12. package/dist/types/modules/checkout/components/checkout-stripe-form.component.d.ts +2 -1
  13. package/dist/types/modules/product-list/components/card-components/index.d.ts +3 -0
  14. package/dist/types/modules/product-list/components/card-components/product-badge.d.ts +8 -0
  15. package/dist/types/modules/product-list/components/card-components/product-fulfillments.d.ts +2 -0
  16. package/dist/types/modules/product-list/components/card-components/product-price-and-personalization.d.ts +13 -0
  17. package/dist/types/modules/product-list/components/card-components/product-title.d.ts +6 -0
  18. package/dist/types/modules/product-list/components/index.d.ts +1 -0
  19. package/dist/types/modules/product-list/components/product-list-engraving.component.d.ts +5 -1
  20. package/dist/types/modules/product-list/components/product-list-product-pre-cart.component.d.ts +28 -0
  21. package/dist/types/modules/product-list/components/product-list-retailers.component.d.ts +10 -2
  22. package/dist/types/modules/product-list/product-list-card.component.d.ts +0 -5
  23. package/dist/types/modules/product-list/product-list.commands.d.ts +11 -2
  24. package/dist/types/modules/product-list/product-list.interface.d.ts +1 -0
  25. package/dist/types/modules/ui-components/engraving/engraving-form.component.d.ts +11 -2
  26. package/dist/types/modules/ui-components/lce-element/lce-element.component.d.ts +2 -1
  27. package/dist/types/utils/dom-compat.d.ts +2 -0
  28. package/docs/gitbook/actions.md +964 -0
  29. package/docs/gitbook/address.md +48 -0
  30. package/docs/gitbook/cart.md +65 -0
  31. package/docs/gitbook/checkout.md +131 -0
  32. package/docs/gitbook/events.md +1765 -0
  33. package/docs/gitbook/overview.md +166 -0
  34. package/docs/gitbook/product.md +64 -0
  35. package/docs/gitbook/quick-start-guide.md +393 -0
  36. package/docs/v1/README.md +210 -0
  37. package/docs/v1/api/actions/address-actions.md +281 -0
  38. package/docs/v1/api/actions/cart-actions.md +337 -0
  39. package/docs/v1/api/actions/checkout-actions.md +387 -0
  40. package/docs/v1/api/actions/product-actions.md +115 -0
  41. package/docs/v1/api/client.md +482 -0
  42. package/docs/v1/api/configuration.md +1 -0
  43. package/docs/v1/api/injection-methods.md +247 -0
  44. package/docs/v1/api/typescript-types.md +1 -0
  45. package/docs/v1/api/ui-helpers.md +200 -0
  46. package/docs/v1/examples/advanced-patterns.md +96 -0
  47. package/docs/v1/examples/checkout-flow.md +91 -0
  48. package/docs/v1/examples/custom-theming.md +63 -0
  49. package/docs/v1/examples/multi-product-page.md +90 -0
  50. package/docs/v1/examples/simple-product-page.md +89 -0
  51. package/docs/v1/getting-started/concepts.md +507 -0
  52. package/docs/v1/getting-started/installation.md +328 -0
  53. package/docs/v1/getting-started/quick-start.md +405 -0
  54. package/docs/v1/guides/address-component.md +431 -0
  55. package/docs/v1/guides/best-practices.md +324 -0
  56. package/docs/v1/guides/cart-component.md +737 -0
  57. package/docs/v1/guides/checkout-component.md +672 -0
  58. package/docs/v1/guides/events.md +926 -0
  59. package/docs/v1/guides/product-component.md +686 -0
  60. package/docs/v1/guides/product-list-component.md +598 -0
  61. package/docs/v1/guides/theming.md +216 -0
  62. package/docs/v1/integration/angular.md +39 -0
  63. package/docs/v1/integration/laravel.md +41 -0
  64. package/docs/v1/integration/nextjs.md +60 -0
  65. package/docs/v1/integration/proxy-setup.md +89 -0
  66. package/docs/v1/integration/react.md +64 -0
  67. package/docs/v1/integration/vanilla-js.md +84 -0
  68. package/docs/v1/integration/vue.md +34 -0
  69. package/docs/v1/reference/browser-support.md +44 -0
  70. package/docs/v1/reference/error-handling.md +70 -0
  71. package/docs/v1/reference/performance.md +54 -0
  72. package/docs/v1/reference/troubleshooting.md +64 -0
  73. package/package.json +1 -1
  74. package/docs/ACTIONS.md +0 -1301
  75. package/docs/BROWSER_SUPPORT.md +0 -279
  76. package/docs/CONFIGURATION.md +0 -997
  77. package/docs/DOCUMENTATION_INDEX.md +0 -319
  78. package/docs/EVENTS.md +0 -798
  79. package/docs/PROXY.md +0 -228
  80. package/docs/THEMING.md +0 -681
  81. package/docs/TROUBLESHOOTING.md +0 -793
package/README.md CHANGED
@@ -9,2813 +9,146 @@ Elements SDK
9
9
 
10
10
  [![JavaScript](https://img.shields.io/badge/JavaScript-ES6+-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black)](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
11
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-5+-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
12
- [![pnpm](https://img.shields.io/badge/pnpm-10+-F69220?style=for-the-badge&logo=pnpm&logoColor=white)](https://pnpm.io/)
13
- [![Rollup](https://img.shields.io/badge/Rollup-4+-EC4A3F?style=for-the-badge&logo=rollup.js&logoColor=white)](https://rollupjs.org/)
14
- ![BiomeJs 2+](https://img.shields.io/badge/BiomeJs-2+-60a5fa?style=for-the-badge&logo=biome&logoColor=white)
15
-
16
- [![License: UNLICENSED](https://img.shields.io/badge/License-UNLICENSED-red.svg)](LICENSE)
17
- [![Zero Dependencies](https://img.shields.io/badge/Dependencies-Zero-brightgreen)](./package.json)
18
- [![Browser Support](https://img.shields.io/badge/Browsers-2018+-4285F4?logo=googlechrome&logoColor=white)](./docs/BROWSER_SUPPORT.md)
19
-
20
- **Add product, cart, and checkout experiences to any website with a few lines of code**
21
-
22
- </div>
23
-
24
- ## 📋 Table of Contents
25
-
26
- <details>
27
- <summary>Click to expand</summary>
28
-
29
- - [Overview](#-overview)
30
- - [Quick Start](#-quick-start)
31
- - [Advanced Usage](#-advanced-usage)
32
- - [Browser Support](#-browser-support)
33
- - [Configuration](#-configuration)
34
- - [SDK Methods & API](#-sdk-methods--api)
35
- - [Actions](#-actions)
36
- - [Events](#-events)
37
- - [Themes & Customization](#-themes--customization)
38
- - [Features Deep Dive](#-features-deep-dive)
39
- - [Core Capabilities](#-core-capabilities)
40
- - [Integration Patterns](#-integration-patterns)
41
- - [Error Handling](#-error-handling)
42
- - [Performance & Best Practices](#-performance--best-practices)
43
- - [Proxy Configuration](#-proxy-configuration)
44
- - [Documentation](#-documentation)
45
- - [Versioning](#-versioning)
46
- - [Support](#-support)
47
-
48
- </details>
49
-
50
- ## 🎯 Overview
51
-
52
- The LiquidCommerce Elements SDK is a **production-ready JavaScript library** that enables partners to seamlessly integrate product displays, shopping carts, and checkout flows into any website. Built with performance and developer experience in mind.
53
-
54
- ### ✨ Key Features
55
-
56
- <table>
57
- <tr>
58
- <td width="50%">
59
-
60
- **🚀 Quick Integration**
61
- - Auto-initialization with data attributes
62
- - Zero configuration setup
63
- - CDN or NPM installation
64
- - Works with any framework or vanilla JS
65
-
66
- </td>
67
- <td width="50%">
68
-
69
- **🛍️ Complete E-commerce**
70
- - Product display components
71
- - Product list with filters and search
72
- - Shopping cart with real-time updates
73
- - Full checkout flow (drawer or hosted page)
74
- - Address management
75
-
76
- </td>
77
- </tr>
78
- <tr>
79
- <td width="50%">
80
-
81
- **🎨 Customizable UI**
82
- - Comprehensive theme system
83
- - Component-level styling
84
- - Responsive design
85
- - Modern, accessible components
86
-
87
- </td>
88
- <td width="50%">
89
-
90
- **⚡ Performance First**
91
- - ~150KB bundle size
92
- - Zero runtime dependencies
93
- - Lazy loading support
94
- - Optimized for Core Web Vitals
95
-
96
- </td>
97
- </tr>
98
- </table>
99
-
100
- ## 🚀 Quick Start
101
-
102
- The fastest way to add e-commerce to your site is with **auto-initialization** - a single script tag that does everything.
103
-
104
- ### The Simplest Setup (30 seconds)
105
-
106
- Add this single script tag to your page:
107
-
108
- ```html
109
- <script
110
- data-liquid-commerce-elements
111
- data-token="YOUR_API_KEY"
112
- data-env="production"
113
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
114
- ></script>
115
- ```
116
-
117
- That's it! You now have:
118
- - ✅ A floating cart button (bottom right)
119
- - ✅ Full cart functionality
120
- - ✅ Complete checkout flow
121
- - ✅ Ready to add products
122
-
123
- ### Adding Products to Your Page
124
-
125
- Now let's display products. Choose the method that fits your use case:
126
-
127
- #### Method 1: Direct Attributes (Best for static pages)
128
-
129
- Add products directly in the script tag:
130
-
131
- ```html
132
- <div id="product-1"></div>
133
- <div id="product-2"></div>
134
-
135
- <script
136
- data-liquid-commerce-elements
137
- data-token="YOUR_API_KEY"
138
- data-env="production"
139
- data-container-1="product-1"
140
- data-product-1="00619947000020"
141
- data-container-2="product-2"
142
- data-product-2="00832889005513"
143
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
144
- ></script>
145
- ```
146
-
147
- **Use case:** Static HTML pages with known products
148
-
149
- #### Method 2: JSON Configuration (Best for CMS/dynamic content)
150
-
151
- Configure products via a JSON script block:
152
-
153
- ```html
154
- <div id="product-1"></div>
155
- <div id="product-2"></div>
156
-
157
- <script data-liquid-commerce-elements-products type="application/json">
158
- [
159
- { "containerId": "product-1", "identifier": "00619947000020" },
160
- { "containerId": "product-2", "identifier": "00832889005513" }
161
- ]
162
- </script>
163
-
164
- <script
165
- data-liquid-commerce-elements
166
- data-token="YOUR_API_KEY"
167
- data-env="production"
168
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
169
- ></script>
170
- ```
171
-
172
- **Use case:** CMS platforms, templating engines, server-side rendering
173
-
174
- #### Method 3: Annotated Elements (Best for grids/lists)
175
-
176
- Mark any div with a data attribute:
177
-
178
- ```html
179
- <div class="product-grid">
180
- <div data-lce-product="00619947000020"></div>
181
- <div data-lce-product="00832889005513"></div>
182
- <div data-lce-product="00851468007252"></div>
183
- </div>
184
-
185
- <script
186
- data-liquid-commerce-elements
187
- data-token="YOUR_API_KEY"
188
- data-env="production"
189
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
190
- ></script>
191
- ```
192
-
193
- **Use case:** Product grids, category pages, search results
194
-
195
- ### Adding a Product List
196
-
197
- Display a filtered, paginated product catalog with infinite scroll. Perfect for category pages, catalog pages, and search results.
198
-
199
- Add a product list to any page with a data attribute:
200
-
201
- ```html
202
- <div data-liquid-commerce-elements-products-list
203
- data-rows="3"
204
- data-columns="4"
205
- data-filters="engraving,presale,fulfillment,price,brands"
206
- data-product-url="/product/{upc}">
207
- </div>
208
-
209
- <script
210
- data-liquid-commerce-elements
211
- data-token="YOUR_API_KEY"
212
- data-env="production"
213
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
214
- ></script>
215
- ```
216
-
217
- **Attributes:**
218
- - `data-liquid-commerce-elements-products-list` - Enables product list on this div
219
- - `data-rows` - Number of rows per page (1-10, default: `3`)
220
- - `data-columns` - Number of columns (1-4, default: `4`)
221
- - `data-filters` - Comma-separated filters (see available filters below)
222
- - `data-product-url` - Product URL template with `{upc}` or `{grouping}` placeholder
223
-
224
- **Available filters:** `engraving`, `presale`, `fulfillment`, `price`, `brands`, `categories`, `flavor`, `region`, `variety`, `vintage`, `country`, `appellation`, `materials`, `sizes`
225
-
226
- **Use case:** Category pages, catalog pages, search results, filtered product browsing
227
-
228
- ### Customizing the Cart Button
229
-
230
- By default, you get a floating cart button with badge. Here's how to customize it:
231
-
232
- #### Option 1: Cart Button in a Specific Container
233
-
234
- ```html
235
- <nav>
236
- <div id="header-cart"></div>
237
- </nav>
238
-
239
- <script
240
- data-liquid-commerce-elements
241
- data-token="YOUR_API_KEY"
242
- data-env="production"
243
- data-cart-badge-button="header-cart"
244
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
245
- ></script>
246
- ```
247
-
248
- **Position Options:**
249
-
250
- You can control where the cart button is placed relative to a target element:
251
-
252
- ```html
253
- <!-- Place inside the target (default) -->
254
- <script data-cart-badge-button="header-cart" ...></script>
255
-
256
- <!-- Place above the target -->
257
- <script data-cart-badge-button="above:.header-logo" ...></script>
258
-
259
- <!-- Place below the target -->
260
- <script data-cart-badge-button="below:#main-nav" ...></script>
261
-
262
- <!-- Replace the target -->
263
- <script data-cart-badge-button="replace:.old-cart" ...></script>
264
- ```
265
-
266
- **ID Auto-Prefixing:**
267
-
268
- Element IDs are automatically prefixed with `#` if needed:
269
-
270
- ```html
271
- <!-- These are equivalent: -->
272
- <script data-cart-button="header-cart" ...></script>
273
- <script data-cart-button="#header-cart" ...></script>
274
- ```
275
-
276
- #### Option 2: Floating Cart Button (Default)
277
-
278
- If no cart button attribute is provided, or if the target element is not found, the SDK automatically falls back to a floating cart button (bottom-right corner):
279
-
280
- ```html
281
- <!-- Empty attribute = floating cart button without badge -->
282
- <script data-cart-button="" ...></script>
283
-
284
- <!-- Empty badge attribute = floating cart button with badge -->
285
- <script data-cart-badge-button="" ...></script>
286
-
287
- <!-- Or simply omit the attribute for floating button with badge -->
288
- <script
289
- data-liquid-commerce-elements
290
- data-token="YOUR_API_KEY"
291
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
292
- ></script>
293
- ```
294
-
295
- #### Option 3: Separate Mobile Cart Button
296
-
297
- Configure different cart button placements for desktop and mobile:
298
-
299
- ```html
300
- <script
301
- data-liquid-commerce-elements
302
- data-token="YOUR_API_KEY"
303
- data-env="production"
304
- data-cart-badge-button="above:.desktop-nav"
305
- data-cart-mobile-badge-button="below:.mobile-header"
306
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
307
- ></script>
308
- ```
309
-
310
- **Mobile button attributes:**
311
- - `data-cart-mobile-button` - Mobile cart button (no badge)
312
- - `data-cart-mobile-badge-button` - Mobile cart button with item count badge
313
-
314
- These support the same position prefixes as the desktop attributes (`above:`, `below:`, `replace:`, `inside:`).
315
-
316
- **Use case:** Different navigation layouts for desktop and mobile
317
-
318
- #### Option 4: Custom Cart Toggle Button
319
-
320
- Use your own button element to toggle the cart:
321
-
322
- ```html
323
- <button data-lce-cart-toggle-button>My Cart</button>
324
- <span data-lce-cart-items-count>0</span>
325
-
326
- <script
327
- data-liquid-commerce-elements
328
- data-token="YOUR_API_KEY"
329
- data-env="production"
330
- data-cart-button-hidden
331
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
332
- ></script>
333
- ```
334
-
335
- **Attributes:**
336
- - `data-lce-cart-toggle-button` - Any element with this attribute becomes a cart toggle
337
- - `data-lce-cart-items-count` - Auto-updates with cart item count. Use value `"keep-zero"` to show count even when cart is empty
338
-
339
- **Use case:** Fully custom cart button with your own styling
340
-
341
- #### Option 5: No Cart Button (Manual Control)
342
-
343
- Hide the cart button completely when you want to manage cart access manually:
344
-
345
- ```html
346
- <script
347
- data-liquid-commerce-elements
348
- data-token="YOUR_API_KEY"
349
- data-env="production"
350
- data-cart-button-hidden
351
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
352
- ></script>
353
- ```
354
-
355
- **Use case:** When you have a custom cart implementation or want to trigger cart display programmatically using `client.actions.cart.openCart()`
356
-
357
- ### Advanced Auto-Init Features
358
-
359
- #### Add Product via URL (Marketing Links)
360
-
361
- Enable "add to cart" via URL parameters for email campaigns and ads:
362
-
363
- ```html
364
- <script
365
- data-liquid-commerce-elements
366
- data-token="YOUR_API_KEY"
367
- data-env="production"
368
- data-product-param="lce_product"
369
- data-product-fulfillment-type-param="lce_fulfillment"
370
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
371
- ></script>
372
- ```
373
-
374
- Now this URL auto-adds a product to cart:
375
- ```
376
- https://yoursite.com/shop?lce_product=00619947000020&lce_fulfillment=shipping
377
- ```
378
-
379
- **Use case:** Email campaigns, social media ads, QR codes
380
-
381
- #### Apply Promo Code via URL (Campaign Tracking)
382
-
383
- Auto-apply promo codes from URL parameters:
384
-
385
- ```html
386
- <script
387
- data-liquid-commerce-elements
388
- data-token="YOUR_API_KEY"
389
- data-env="production"
390
- data-promo-code-param="lce_promo"
391
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
392
- ></script>
393
- ```
394
-
395
- Now this URL auto-applies a promo code:
396
- ```
397
- https://yoursite.com/shop?lce_promo=SUMMER20
398
- ```
399
-
400
- **Use case:** Promotional campaigns, influencer codes, affiliate links
401
-
402
- #### Promo Ticker (Rotating Promotions)
403
-
404
- Display rotating promotional messages:
405
-
406
- ```html
407
- <script
408
- data-liquid-commerce-elements
409
- data-token="YOUR_API_KEY"
410
- data-env="production"
411
- data-promo-code="FREESHIP"
412
- data-promo-text="Free Shipping Today Only!|Use code FREESHIP at checkout"
413
- data-promo-separator="•"
414
- data-promo-active-from="2025-01-01T00:00:00Z"
415
- data-promo-active-until="2025-01-31T23:59:59Z"
416
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
417
- ></script>
418
- ```
419
-
420
- **Use case:** Time-sensitive promotions, holiday sales, flash deals
421
-
422
- #### Debug Mode (Development)
423
-
424
- Enable debug logging during development:
425
-
426
- ```html
427
- <script
428
- data-liquid-commerce-elements
429
- data-token="YOUR_API_KEY"
430
- data-env="development"
431
- data-debug-mode="console"
432
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
433
- ></script>
434
- ```
435
-
436
- **Debug modes:**
437
- - `console` - Logs to browser console
438
- - `panel` - Shows visual debug panel + console logs
439
- - Not set - No debugging (production default)
440
-
441
- ### Complete Auto-Init Reference
442
-
443
- Here's every available data attribute:
444
-
445
- ```html
446
- <script
447
- data-liquid-commerce-elements
448
-
449
- <!-- Required -->
450
- data-token="YOUR_API_KEY"
451
-
452
- <!-- Environment -->
453
- data-env="production|staging|development|local"
454
-
455
- <!-- Cart Button (Desktop) -->
456
- data-cart-button="container-id" <!-- Simple cart button (no badge) -->
457
- data-cart-badge-button="container-id" <!-- Cart button with badge -->
458
- data-cart-button-hidden <!-- Hide cart button completely -->
459
-
460
- <!-- Cart Button (Mobile) -->
461
- data-cart-mobile-button="container-id" <!-- Mobile cart button (no badge) -->
462
- data-cart-mobile-badge-button="container-id" <!-- Mobile cart button with badge -->
463
-
464
- <!-- Cart Button with Position Prefixes -->
465
- data-cart-button="above:.logo" <!-- Place above target -->
466
- data-cart-badge-button="below:#header" <!-- Place below target -->
467
- data-cart-button="inside:.nav" <!-- Place inside target (default) -->
468
- data-cart-badge-button="replace:.old-cart" <!-- Replace target -->
469
-
470
- <!-- Cart Button Floating (empty values) -->
471
- data-cart-button="" <!-- Floating button without badge -->
472
- data-cart-badge-button="" <!-- Floating button with badge -->
473
-
474
- <!-- Products (Method 1: Direct) -->
475
- data-container-1="div-id"
476
- data-product-1="identifier"
477
- data-container-2="div-id"
478
- data-product-2="identifier"
479
-
480
- <!-- URL Parameters -->
481
- data-product-param="lce_product"
482
- data-product-fulfillment-type-param="lce_fulfillment"
483
- data-promo-code-param="lce_promo"
484
-
485
- <!-- Promo Ticker -->
486
- data-promo-code="CODE"
487
- data-promo-text="Message 1|Message 2"
488
- data-promo-separator="•"
489
- data-promo-active-from="2025-01-01T00:00:00Z"
490
- data-promo-active-until="2025-12-31T23:59:59Z"
491
-
492
- <!-- Checkout Page (Hosted Checkout) -->
493
- data-checkout-url="https://yoursite.com/checkout?id={id}"
494
-
495
- <!-- Debugging (dev only) -->
496
- data-debug-mode="console|panel"
497
-
498
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
499
- ></script>
500
-
501
- <!-- Product List (on separate div element) -->
502
- <div data-liquid-commerce-elements-products-list
503
- data-rows="3"
504
- data-columns="4"
505
- data-filters="engraving,presale,fulfillment,price,brands"
506
- data-product-url="/product/{upc}">
507
- </div>
508
-
509
- <!-- Custom Cart Toggle Button (on any button/element) -->
510
- <button data-lce-cart-toggle-button>My Cart</button>
511
-
512
- <!-- Custom Cart Items Count Display (on any element) -->
513
- <span data-lce-cart-items-count>0</span>
514
- <!-- Use "keep-zero" value to always show count, even when 0 -->
515
- <span data-lce-cart-items-count="keep-zero">0</span>
516
- ```
517
-
518
- **📖 For complete auto-init options:** See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for all data attributes and configuration details.
519
-
520
- ### Hosted Checkout (External Checkout Page)
521
-
522
- Instead of using the default checkout drawer, you can redirect customers to a dedicated checkout page on your site. This is useful when you want a full-page checkout experience.
523
-
524
- #### Auto-Init Setup
525
-
526
- ```html
527
- <!-- On your product/cart pages -->
528
- <script
529
- data-liquid-commerce-elements
530
- data-token="YOUR_API_KEY"
531
- data-env="production"
532
- data-checkout-url="https://yoursite.com/checkout?id={id}"
533
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
534
- ></script>
535
- ```
536
-
537
- When `data-checkout-url` is set, the "Go to Checkout" button in the cart will redirect to that URL instead of opening the checkout drawer. The `{id}` placeholder is replaced with the checkout token generated by the SDK.
538
-
539
- #### Checkout Page Setup
540
-
541
- On your dedicated checkout page, use the **checkout-only build** for a smaller bundle:
542
-
543
- ```html
544
- <div id="checkout-container"></div>
545
-
546
- <script
547
- data-liquid-commerce-checkout
548
- data-token="YOUR_API_KEY"
549
- data-env="production"
550
- src="https://assets-elements.liquidcommerce.us/checkout/elements.js"
551
- ></script>
552
- ```
553
-
554
- Or initialize programmatically:
555
-
556
- ```js
557
- import { ElementsCheckout } from '@liquidcommerce/elements-sdk/checkout';
558
-
559
- const client = await ElementsCheckout('YOUR_API_KEY', {
560
- env: 'production'
561
- });
562
-
563
- // Inject checkout, optionally passing the checkout token from the URL
564
- const urlParams = new URLSearchParams(window.location.search);
565
- const component = await client.injectCheckout({
566
- containerId: 'checkout-container',
567
- checkoutId: urlParams.get('id'), // The checkout token from the URL
568
- hideHeader: true
569
- });
570
- ```
571
-
572
- **Checkout-only build features:**
573
- - Smaller bundle size (tree-shaken, no product/cart/PLP components)
574
- - All checkout actions available (`actions.checkout.*`)
575
- - Same theming and event system as the full SDK
576
- - Auto-initialization via `data-liquid-commerce-checkout` attribute
577
-
578
- **Use case:** Dedicated checkout pages, custom checkout flows, multi-page checkout
579
-
580
- #### Programmatic Setup (Full SDK)
581
-
582
- You can also configure hosted checkout programmatically with the full SDK:
583
-
584
- ```js
585
- const client = await Elements('YOUR_API_KEY', {
586
- env: 'production',
587
- checkout: {
588
- pageUrl: 'https://yoursite.com/checkout?id={id}'
589
- }
590
- });
591
- ```
592
-
593
- ---
594
-
595
- ## 🔧 Advanced Usage
596
-
597
- Need more control? Initialize programmatically for full access to the SDK API.
598
-
599
- ### Installation
600
-
601
- **CDN:**
602
- ```html
603
- <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
604
-
605
- <!-- Pin to specific version: -->
606
- <script src="https://assets-elements.liquidcommerce.us/all/1.2.3/elements.js"></script>
607
- ```
608
-
609
- **NPM:**
610
- ```bash
611
- npm install @liquidcommerce/elements-sdk
612
- # or
613
- pnpm add @liquidcommerce/elements-sdk
614
- ```
615
-
616
- ### Programmatic Initialization
617
-
618
- ```html
619
- <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
620
- <script>
621
- (async () => {
622
- const client = await window.Elements('YOUR_API_KEY', {
623
- env: 'production',
624
- debugMode: 'none',
625
- customTheme: { /* theming overrides */ },
626
- proxy: { /* proxy config */ }
627
- });
628
-
629
- // Inject components
630
- const components = await client.injectProductElement([
631
- { containerId: 'pdp-1', identifier: '00619947000020' }
632
- ]);
633
-
634
- // Create cart button
635
- client.ui.cartButton('cart-container', true);
636
-
637
- // Use actions API
638
- await client.actions.cart.addProduct([{
639
- identifier: '00619947000020',
640
- fulfillmentType: 'shipping',
641
- quantity: 1
642
- }]);
643
- })();
644
- </script>
645
- ```
646
-
647
- **NPM Import:**
648
- ```js
649
- import { Elements } from '@liquidcommerce/elements-sdk';
650
-
651
- const client = await Elements('YOUR_API_KEY', { env: 'production' });
652
- ```
653
-
654
- ---
655
-
656
- ## 🌐 Browser Support
657
-
658
- ⚠️ **Important**: This SDK is designed for browser environments only. It will not work in server-side rendering, Node.js, or other non-browser environments.
659
-
660
- ### Supported Browsers (2018+)
661
-
662
- | Browser | Minimum Version | Released |
663
- |---------|----------------|----------|
664
- | Chrome | 66+ | April 2018 |
665
- | Firefox | 60+ | May 2018 |
666
- | Safari | 12+ | September 2018 |
667
- | Edge | 79+ (Chromium) | January 2020 |
668
- | Samsung Internet | 7.2+ | June 2018 |
669
-
670
- 📖 See [`docs/BROWSER_SUPPORT.md`](docs/BROWSER_SUPPORT.md) for detailed compatibility.
671
-
672
- ## ⚙️ Configuration
673
-
674
- ### Basic Configuration
675
-
676
- ```js
677
- const client = await Elements('YOUR_API_KEY', {
678
- env: 'production', // Environment
679
- debugMode: 'none', // Debug mode
680
- customTheme: { }, // Theme overrides
681
- proxy: { }, // Proxy configuration
682
- promoTicker: [ ], // Promotional messages
683
- checkout: { // Hosted checkout configuration
684
- pageUrl: 'https://yoursite.com/checkout?id={id}'
685
- }
686
- });
687
- ```
688
-
689
- ### Environment Options
690
-
691
- ```js
692
- env: 'production' // Live environment (default)
693
- env: 'staging' // Pre-production testing
694
- env: 'development' // Development with extra logging
695
- env: 'local' // Local development
696
- ```
697
-
698
- ### Debug Modes
699
-
700
- ```js
701
- debugMode: 'none' // No debugging (production default)
702
- debugMode: 'console' // Console logs only
703
- debugMode: 'panel' // Visual debug panel + console logs
704
- ```
705
-
706
- **Note:** Debug mode is automatically disabled in production environment for security.
707
-
708
- ### Custom Theme
709
-
710
- Override default styles and layouts:
711
-
712
- ```js
713
- customTheme: {
714
- global: {
715
- theme: {
716
- primaryColor: '#007bff',
717
- accentColor: '#6c757d',
718
- successColor: '#28a745',
719
- errorColor: '#dc3545',
720
- buttonCornerRadius: '8px',
721
- cardCornerRadius: '12px',
722
- headingFont: {
723
- name: 'Inter',
724
- weights: [600, 700]
725
- },
726
- paragraphFont: {
727
- name: 'Inter',
728
- weights: [400, 500]
729
- }
730
- },
731
- layout: {
732
- allowPromoCodes: true,
733
- inputFieldStyle: 'outlined'
734
- }
735
- },
736
- product: {
737
- layout: {
738
- showDescription: true,
739
- addToCartButtonText: 'Add to Cart',
740
- fulfillmentDisplay: 'carousel'
741
- }
742
- },
743
- cart: {
744
- layout: {
745
- showQuantityCounter: true,
746
- drawerHeaderText: 'Your Cart'
747
- }
748
- },
749
- checkout: {
750
- layout: {
751
- allowGiftCards: true,
752
- emailOptIn: { show: true, checked: false, text: 'Email me with news' },
753
- smsOptIn: { show: true, checked: false, text: 'Text me with updates' }
754
- }
755
- }
756
- }
757
- ```
758
-
759
- **📖 For complete theming options:** See [`docs/THEMING.md`](docs/THEMING.md)
760
-
761
- ### Proxy Configuration
762
-
763
- Route API requests through your server to avoid ad blockers:
764
-
765
- ```js
766
- proxy: {
767
- baseUrl: 'https://yourdomain.com/api/proxy',
768
- headers: {
769
- 'X-Custom-Auth': 'your-token'
770
- }
771
- }
772
- ```
773
-
774
- See [`docs/PROXY.md`](docs/PROXY.md) for implementation guide.
775
-
776
- ### Promo Ticker
777
-
778
- Display rotating promotional messages:
779
-
780
- ```js
781
- promoTicker: [
782
- {
783
- promoCode: 'FREESHIP',
784
- text: ['Free Shipping Today!', 'Use code FREESHIP'],
785
- separator: '•',
786
- activeFrom: '2025-01-01T00:00:00Z',
787
- activeUntil: '2025-12-31T23:59:59Z'
788
- }
789
- ]
790
- ```
791
-
792
- **📖 For all configuration options:** See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for complete reference with TypeScript types.
793
-
794
- ---
795
-
796
- ## 📖 SDK Methods & API
797
-
798
- ### Component Injection
799
-
800
- Inject SDK components into your page containers. All injection methods return wrapper objects that provide component control.
801
-
802
- #### Products
803
-
804
- ```js
805
- const components = await client.injectProductElement([
806
- { containerId: 'pdp-1', identifier: '00619947000020' },
807
- { containerId: 'pdp-2', identifier: '00832889005513' }
808
- ]);
809
-
810
- // Returns: IInjectedComponent[] - Array of component wrappers
811
- // components[0].rerender() - Rerender the first component
812
- // components[0].getElement() - Get the container element
813
- // components[0].getType() - Get component type
814
- ```
815
-
816
- **Identifier types:** UPC, product ID, or Salsify grouping ID
817
-
818
- #### Cart
819
-
820
- ```js
821
- const component = await client.injectCartElement('cart-container');
822
-
823
- // Returns: IInjectedComponent | null - Component wrapper or null if failed
824
- // component.rerender() - Rerender the component
825
- // component.getElement() - Get the container element
826
- // component.getType() - Get component type
827
- ```
828
-
829
- **Use case:** Dedicated cart page
830
-
831
- #### Checkout
832
-
833
- ```js
834
- const component = await client.injectCheckoutElement({
835
- containerId: 'checkout-container',
836
- checkoutId: 'checkout-token', // Optional: load specific checkout by checkout token
837
- hideHeader: false // Optional: hide checkout header in standalone mode
838
- });
839
-
840
- // Returns: IInjectedComponent | null - Component wrapper or null if failed
841
- // component.rerender() - Rerender the component
842
- // component.getElement() - Get the container element
843
- // component.getType() - Get component type
844
- ```
845
-
846
- **Parameters:**
847
- - `containerId` (required) - Where to inject the checkout
848
- - `checkoutId` (optional) - Checkout token to load a specific checkout session
849
- - `hideHeader` (optional) - Hide the checkout header when used in standalone/hosted mode
850
-
851
- **Use case:** Dedicated checkout page, hosted checkout
852
-
853
- #### Address
854
-
855
- ```js
856
- const component = await client.injectAddressElement('address-container');
857
-
858
- // Returns: IInjectedComponent | null - Component wrapper or null if failed
859
- // component.rerender() - Rerender the component
860
- // component.getElement() - Get the container element
861
- // component.getType() - Get component type
862
- ```
863
-
864
- **Use case:** Shipping address collection page
865
-
866
- #### Product List
867
-
868
- ```js
869
- await client.injectProductList({
870
- containerId: 'product-list-container',
871
- rows: 3, // Number of rows per page (1-10)
872
- columns: 4, // Number of columns (1-4)
873
- filters: [ // Optional filters
874
- 'engraving', // Engravable/personalizable products
875
- 'presale', // Pre-order products
876
- 'fulfillment', // Delivery type filter (shipping, onDemand)
877
- 'price', // Price range filter
878
- 'brands', // Brand filter
879
- 'categories', // Category filter
880
- 'flavor', // Flavor filter
881
- 'region', // Region filter
882
- 'variety', // Variety filter
883
- 'vintage', // Vintage filter
884
- 'country', // Country filter
885
- 'appellation', // Appellation filter
886
- 'materials', // Materials filter
887
- 'sizes' // Size filter
888
- ],
889
- productUrl: '/product/{upc}' // Optional: Product detail page URL template
890
- });
891
- ```
892
-
893
- **Parameters:**
894
- - `containerId` - Where to inject the product list
895
- - `rows` - Number of rows to display per page (1-10, default: `3`)
896
- - `columns` - Number of columns in the grid (1-4, default: `4`)
897
- - `filters` - Array of filter types to enable (see available filters below)
898
- - `productUrl` - Optional URL template for product links. Use `{upc}` or `{grouping}` placeholder
899
-
900
- **Available filters:** `engraving`, `presale`, `fulfillment`, `price`, `brands`, `categories`, `flavor`, `region`, `variety`, `vintage`, `country`, `appellation`, `materials`, `sizes`
901
-
902
- **Features:**
903
- - ✅ Infinite scroll pagination
904
- - ✅ Rich filtering (14 filter types)
905
- - ✅ Address-aware (reloads when address changes)
906
- - ✅ Loading states and error handling
907
- - ✅ Automatic GTM tracking (`view_item_list`, `select_item`)
908
- - ✅ Add to cart directly from cards
909
- - ✅ Product links with tracking
910
-
911
- **Use case:** Category pages, catalog pages, search results, filtered product browsing
912
-
913
- **Note:** The product list automatically reloads when the address changes to show availability for the new location.
914
-
915
- #### Product List Search
916
-
917
- ```js
918
- await client.injectProductListSearch({
919
- containerId: 'search-container'
920
- });
921
- ```
922
-
923
- Injects a search input component that works with the product list to filter products by keyword.
924
-
925
- **Use case:** Search bars on catalog/category pages
926
-
927
- #### Product List Filters
928
-
929
- ```js
930
- await client.injectProductListFilters({
931
- containerId: 'filters-container',
932
- filters: ['price', 'brands', 'categories', 'variety']
933
- });
934
- ```
935
-
936
- Injects a standalone filter panel component that works with the product list. Use this when you want the filters in a separate container from the product grid (e.g., a sidebar).
937
-
938
- **Parameters:**
939
- - `containerId` - Where to inject the filter panel
940
- - `filters` - Array of filter types to display
941
-
942
- **Use case:** Sidebar filter panels on category pages
943
-
944
- #### Access All Injected Components
945
-
946
- ```js
947
- // Get all injected components
948
- const injectedComponents = client.getInjectedComponents();
949
-
950
- // Access specific components by container ID
951
- const productComponent = injectedComponents.get('product-container-1');
952
- const cartComponent = injectedComponents.get('cart-container');
953
-
954
- // Iterate through all components
955
- injectedComponents.forEach((component, containerId) => {
956
- console.log(`Container: ${containerId}, Type: ${component.getType()}`);
957
-
958
- // Rerender specific components
959
- if (component.getType() === 'product') {
960
- component.rerender();
961
- }
962
- });
963
-
964
- // Get all components of a specific type
965
- const productComponents = Array.from(injectedComponents.values())
966
- .filter(component => component.getType() === 'product');
967
-
968
- // Rerender all components of a type
969
- productComponents.forEach(component => component.rerender());
970
- ```
971
-
972
- **Returns:** `Map<string, IInjectedComponent>` - Map of container IDs to component wrappers
973
-
974
- **Use cases:**
975
- - Debugging and inspecting injected components
976
- - Bulk operations on multiple components
977
- - Component management and cleanup
978
-
979
- ### UI Helpers
980
-
981
- Create standalone UI elements that integrate with the SDK.
982
-
983
- #### Cart Button (in container)
984
-
985
- ```js
986
- client.ui.cartButton('header-cart', true);
987
- ```
988
-
989
- **Parameters:**
990
- - `containerId` - Where to place the button
991
- - `showItemsCount` - Show item count badge (optional)
992
-
993
- **Use case:** Header navigation, sidebar
994
-
995
- #### Floating Cart Button
996
-
997
- ```js
998
- client.ui.floatingCartButton(true);
999
- ```
1000
-
1001
- **Parameters:**
1002
- - `showItemsCount` - Show item count badge (optional)
1003
-
1004
- **Use case:** Always-visible cart access (bottom-right corner)
1005
-
1006
- #### Live Cart Data Display
1007
-
1008
- Bind elements to auto-update with cart data:
1009
-
1010
- ```js
1011
- // Show live subtotal
1012
- client.ui.cartSubtotal('cart-total-display');
1013
-
1014
- // Show live item count (default behavior: hides when count is 0)
1015
- client.ui.cartItemsCount('cart-badge');
1016
-
1017
- // Show live item count (always visible, even when 0)
1018
- client.ui.cartItemsCount('cart-badge', { hideZero: false });
1019
- ```
1020
-
1021
- **Parameters for `cartItemsCount`:**
1022
- - `elementId` (string) - ID of the element to update
1023
- - `options` (object, optional) - Configuration options:
1024
- - `hideZero` (boolean, default: `true`) - When `true`, element is hidden when cart count is 0. When `false`, element remains visible showing "0".
1025
-
1026
- **Example:**
1027
- ```html
1028
- <nav>
1029
- <span>Cart: $<span id="cart-total-display">0.00</span></span>
1030
- <span>(<span id="cart-badge">0</span> items)</span>
1031
- </nav>
1032
-
1033
- <script>
1034
- // Default behavior - badge hidden when cart is empty
1035
- client.ui.cartItemsCount('cart-badge');
1036
-
1037
- // Always show count, even when 0
1038
- client.ui.cartItemsCount('cart-badge', { hideZero: false });
1039
- </script>
1040
- ```
1041
-
1042
- ### Builder Methods (Development Mode)
1043
-
1044
- When `isBuilder: true` is set, additional methods are available for theme customization:
1045
-
1046
- ```js
1047
- const client = await Elements('YOUR_API_KEY', {
1048
- env: 'development',
1049
- isBuilder: true
1050
- });
1051
-
1052
- // Update component themes
1053
- await client.builder.updateComponentGlobalConfigs(globalTheme);
1054
- await client.builder.updateProductComponent(productTheme);
1055
- client.builder.updateCartComponent(cartTheme);
1056
- client.builder.updateCheckoutComponent(checkoutTheme);
1057
- client.builder.updateAddressComponent(addressTheme);
1058
-
1059
- // Builder injection methods (same as regular methods)
1060
- const components = await client.builder.injectProductElement(params);
1061
- const component = await client.builder.injectCartElement(containerId);
1062
- const checkoutComponent = await client.builder.injectCheckoutElement({
1063
- containerId,
1064
- checkoutId, // Optional
1065
- hideHeader // Optional
1066
- });
1067
- const addressComponent = await client.builder.injectAddressElement(containerId);
1068
-
1069
- // All return IInjectedComponent wrapper objects with rerender(), getElement(), getType() methods
1070
- ```
1071
-
1072
- ## 🎬 Actions
1073
-
1074
- Actions provide programmatic control over SDK components. Access them via `client.actions` or `window.elements.actions`:
1075
-
1076
- ```js
1077
- // Available after client initialization
1078
- const actions = client.actions;
1079
- // OR globally
1080
- const actions = window.elements.actions;
1081
- ```
1082
-
1083
- ### Product Actions
1084
-
1085
- ```js
1086
- // Get product details
1087
- const product = actions.product.getDetails('product-123');
1088
- console.log(product.name, product.brand, product.region, product.variety);
1089
- console.log(product.priceInfo, product.description, product.tastingNotes);
1090
- ```
1091
-
1092
- ### Address Actions
1093
-
1094
- ```js
1095
- // Set address using Google Places ID
1096
- await actions.address.setAddressByPlacesId('ChIJ0SRjyK5ZwokRp1TwT8dJSv8');
1097
-
1098
- // Set address manually without Google Places (perfect for custom address forms)
1099
- await actions.address.setAddressManually(
1100
- {
1101
- one: '123 Main St',
1102
- two: 'Apt 4B', // Optional apartment/suite
1103
- city: 'New York',
1104
- state: 'NY',
1105
- zip: '10001',
1106
- country: 'United States' // Optional, will be included in formatted address
1107
- },
1108
- {
1109
- lat: 40.7505045,
1110
- long: -73.9934387
1111
- }
1112
- );
1113
-
1114
- // Listen for success/failure via events
1115
- window.addEventListener('lce:actions.address_updated', function(event) {
1116
- const address = event.detail.data;
1117
- console.log('✅ Address set!', address.formattedAddress);
1118
- updateShippingOptions(address.coordinates);
1119
- });
1120
-
1121
- window.addEventListener('lce:actions.address_failed', function(event) {
1122
- const error = event.detail.data;
1123
- console.log('❌ Address failed:', error.message);
1124
- showAddressForm();
1125
- });
1126
-
1127
- // Get current address
1128
- const address = actions.address.getDetails();
1129
-
1130
- // Clear saved address
1131
- actions.address.clear();
1132
- ```
1133
-
1134
- #### Clear Address - Complete Reset
1135
-
1136
- The `actions.address.clear()` action performs a comprehensive reset of the user's address and shopping session:
1137
-
1138
- **What it clears:**
1139
- - ✅ **Address Data**: Removes all saved address information (street, city, state, zip, coordinates)
1140
- - ✅ **Cart Contents**: Completely resets the cart (removes all items, totals, promo codes)
1141
- - ✅ **Local Storage**: Completely removes the localStorage entry and its value
1142
- - ✅ **Database**: Deletes the persisted store from the server database
1143
- - ✅ **Checkout State**: Resets any pending checkout information
1144
-
1145
- **Why it resets the cart:**
1146
- When an address is cleared, the cart must be reset because:
1147
- - Cart items have location-specific pricing and availability
1148
- - Fulfillment options are tied to specific addresses
1149
- - Delivery fees and shipping costs depend on location
1150
- - Without a valid address, cart operations would fail or show incorrect data
1151
-
1152
- **Events fired:**
1153
- - `lce:actions.address_cleared` - Address successfully cleared
1154
- - `lce:actions.cart_reset` - Cart successfully reset
1155
-
1156
- **Use cases:**
1157
- - Guest checkout option (clear previous user's data)
1158
- - Location change (start fresh with new address)
1159
- - Privacy compliance (complete data removal)
1160
- - Testing/development (reset to clean state)
1161
-
1162
- **Notes**:
1163
- - To find Google Places IDs for the `setAddressByPlacesId` action, use the [Google Places ID Finder](https://developers.google.com/maps/documentation/places/web-service/place-id#find-id)
1164
- - The `setAddressManually` action automatically generates a Google Places API-formatted address string from the provided components
1165
- - Manual addresses have an empty Places ID (as they don't come from Google Places API)
1166
-
1167
- **Action Feedback**: All actions provide feedback through events. Listen for success/failure events to handle results and provide user feedback.
1168
-
1169
- ### Cart Actions
1170
-
1171
- ```js
1172
- // Control cart visibility
1173
- actions.cart.openCart();
1174
- actions.cart.closeCart();
1175
- actions.cart.toggleCart();
1176
-
1177
- // Add products to cart
1178
- await actions.cart.addProduct([{
1179
- identifier: 'product-123',
1180
- fulfillmentType: 'shipping', // or 'onDemand'
1181
- quantity: 2
1182
- }]);
1183
-
1184
- // Listen for add product feedback
1185
- window.addEventListener('lce:actions.cart_product_add_success', function(event) {
1186
- const { itemsAdded, identifiers } = event.detail.data;
1187
- console.log(`✅ Added ${itemsAdded} products to cart:`, identifiers);
1188
- showSuccessMessage('Products added to cart!');
1189
- });
1190
-
1191
- window.addEventListener('lce:actions.cart_product_add_failed', function(event) {
1192
- const { identifiers, error } = event.detail.data;
1193
- console.log(`❌ Failed to add products:`, error);
1194
- showErrorMessage('Could not add products. Please try again.');
1195
- });
1196
-
1197
- // Apply promo codes
1198
- await actions.cart.applyPromoCode('WELCOME10');
1199
-
1200
- // Listen for promo code feedback
1201
- window.addEventListener('lce:actions.cart_promo_code_applied', function(event) {
1202
- const { discount, newTotal } = event.detail.data;
1203
- console.log(`✅ Promo applied! Discount: $${discount}, New total: $${newTotal}`);
1204
- showSavingsMessage(discount);
1205
- });
1206
-
1207
- window.addEventListener('lce:actions.cart_promo_code_failed', function(event) {
1208
- const { error } = event.detail.data;
1209
- console.log(`❌ Promo failed:`, error);
1210
- showErrorMessage('Promo code could not be applied');
1211
- });
1212
-
1213
- // Remove promo codes
1214
- await actions.cart.removePromoCode();
1215
-
1216
- // Get cart details
1217
- const cart = actions.cart.getDetails();
1218
- console.log(cart.itemCount, cart.amounts.total, cart.amounts.giftCardTotal);
1219
-
1220
- // Reset cart
1221
- await actions.cart.resetCart();
1222
- ```
1223
-
1224
- ### Checkout Actions
1225
-
1226
- ```js
1227
- // Control checkout visibility
1228
- actions.checkout.openCheckout();
1229
- actions.checkout.closeCheckout();
1230
- actions.checkout.toggleCheckout();
1231
- actions.checkout.exitCheckout(); // Exit checkout (return to cart)
1232
-
1233
- // Pre-fill customer information
1234
- actions.checkout.updateCustomerInfo({
1235
- firstName: 'John',
1236
- lastName: 'Doe',
1237
- email: 'john@example.com',
1238
- phone: '+1234567890'
1239
- });
1240
-
1241
- // Pre-fill billing information
1242
- actions.checkout.updateBillingInfo({
1243
- firstName: 'John',
1244
- lastName: 'Doe',
1245
- street1: '123 Main St',
1246
- city: 'Anytown',
1247
- state: 'CA',
1248
- zipCode: '12345'
1249
- });
1250
-
1251
- // Manage gift options
1252
- await actions.checkout.toggleIsGift(true);
1253
- actions.checkout.updateGiftInfo({
1254
- giftMessage: 'Happy Birthday!',
1255
- giftFrom: 'Your Friend'
1256
- });
1257
-
1258
- // Apply discounts and gift cards
1259
- await actions.checkout.applyPromoCode('SAVE20');
1260
- await actions.checkout.applyGiftCard('GIFT123');
1261
-
1262
- // Listen for checkout promo code feedback
1263
- window.addEventListener('lce:actions.checkout_promo_code_applied', function(event) {
1264
- const { discount, newTotal } = event.detail.data;
1265
- console.log(`✅ Checkout promo applied! Saved: $${discount}`);
1266
- updateCheckoutTotal(newTotal);
1267
- });
1268
-
1269
- window.addEventListener('lce:actions.checkout_promo_code_failed', function(event) {
1270
- const { error } = event.detail.data;
1271
- console.log(`❌ Checkout promo failed:`, error);
1272
- showCheckoutError('Promo code could not be applied');
1273
- });
1274
-
1275
- // Listen for gift card feedback
1276
- window.addEventListener('lce:actions.checkout_gift_card_applied', function(event) {
1277
- const { newTotal } = event.detail.data;
1278
- console.log('✅ Gift card applied successfully!');
1279
- updateCheckoutTotal(newTotal);
1280
- showSuccessMessage('Gift card applied to your order');
1281
- });
1282
-
1283
- window.addEventListener('lce:actions.checkout_gift_card_failed', function(event) {
1284
- const { error } = event.detail.data;
1285
- console.log(`❌ Gift card failed:`, error);
1286
- showCheckoutError('Gift card could not be applied');
1287
- });
1288
-
1289
- // Get checkout details (safe, non-sensitive data only)
1290
- const checkout = actions.checkout.getDetails();
1291
- console.log(checkout.itemCount, checkout.amounts.total, checkout.isGift);
1292
- console.log(checkout.hasAgeVerify, checkout.hasPromoCode, checkout.hasGiftCards);
1293
- console.log(checkout.acceptedAccountCreation, checkout.billingSameAsShipping);
1294
- console.log(checkout.marketingPreferences);
1295
-
1296
- // Configure checkout options
1297
- await actions.checkout.toggleBillingSameAsShipping(true);
1298
- actions.checkout.toggleMarketingPreferences('canEmail', true);
1299
- ```
1300
-
1301
- See [`docs/ACTIONS.md`](docs/ACTIONS.md) for complete action reference with business use cases.
1302
-
1303
- ## 📡 Events
1304
-
1305
- The SDK emits real-time events for all user interactions. Listen to these events to trigger custom behavior:
1306
-
1307
- ```js
1308
- // Listen for specific events
1309
- window.addEventListener('lce:actions.product_add_to_cart', function(event) {
1310
- const data = event.detail.data;
1311
- console.log('Added to cart:', data.identifier);
1312
-
1313
- // Your custom logic here
1314
- analytics.track('Product Added', {
1315
- identifier: data.identifier,
1316
- quantity: data.quantity,
1317
- upc: data.upc
1318
- });
1319
- });
1320
-
1321
- // Or use the helper methods (available after initialization)
1322
- window.elements.onAllForms((data, metadata) => {
1323
- console.log('Form Event', { data, metadata });
1324
- });
1325
-
1326
- window.elements.onAllActions((data, metadata) => {
1327
- console.log('Action Event', { data, metadata });
1328
- });
1329
- ```
1330
-
1331
- ### Available Events
1332
-
1333
- #### Product Events
1334
- - `lce:actions.product_loaded` - Product component loaded with comprehensive product details (region, country, abv, proof, age, variety, vintage, descriptions, tasting notes)
1335
- - `lce:actions.product_add_to_cart` - Item added to cart
1336
- - `lce:actions.product_quantity_increase` - Quantity increased
1337
- - `lce:actions.product_quantity_decrease` - Quantity decreased
1338
- - `lce:actions.product_size_changed` - Product size/variant changed
1339
- - `lce:actions.product_fulfillment_type_changed` - Delivery method changed
1340
-
1341
- #### Cart Events
1342
- - `lce:actions.cart_loaded` - Cart data loaded with complete cart information (itemCount, all amounts including giftCardTotal, detailed item data)
1343
- - `lce:actions.cart_opened` - Cart displayed
1344
- - `lce:actions.cart_closed` - Cart hidden
1345
- - `lce:actions.cart_updated` - Cart contents changed
1346
- - `lce:actions.cart_item_added` - Item added
1347
- - `lce:actions.cart_item_removed` - Item removed
1348
- - `lce:actions.cart_reset` - Cart cleared
1349
-
1350
- #### Checkout Events
1351
- - `lce:actions.checkout_loaded` - Checkout data loaded with comprehensive details (acceptedAccountCreation, hasSubstitutionPolicy, billingSameAsShipping, marketing preferences, detailed items)
1352
- - `lce:actions.checkout_opened` - Checkout started
1353
- - `lce:actions.checkout_closed` - Checkout abandoned
1354
- - `lce:actions.checkout_submit_started` - Order submission began
1355
- - `lce:actions.checkout_submit_completed` - Order completed successfully
1356
- - `lce:actions.checkout_submit_failed` - Order failed
1357
- - `lce:actions.checkout_customer_information_updated` - Customer info entered (returns boolean only, no sensitive data)
1358
- - `lce:actions.checkout_gift_information_updated` - Gift recipient info entered (returns boolean only, no sensitive data)
1359
- - `lce:actions.checkout_billing_information_updated` - Billing info entered (returns boolean only, no sensitive data)
1360
-
1361
- **Security Note:** Form update events return only `boolean: true` to track completion without exposing sensitive customer information (names, emails, phone numbers, addresses, etc.). This protects your customers from malicious scripts and data breaches.
1362
-
1363
- #### Address Events
1364
- - `lce:actions.address_updated` - Address information changed
1365
- - `lce:actions.address_cleared` - Address removed
1366
-
1367
- See [`docs/EVENTS.md`](docs/EVENTS.md) for complete event reference with all available fields and implementation examples.
1368
-
1369
- ## 🎨 Themes & Customization
1370
-
1371
- The SDK provides a theming system that lets you match components to your brand.
1372
-
1373
- ### Global Theming
1374
-
1375
- ```js
1376
- const client = await Elements('YOUR_API_KEY', {
1377
- customTheme: {
1378
- global: {
1379
- theme: {
1380
- primaryColor: '#007bff',
1381
- accentColor: '#6c757d',
1382
- successColor: '#28a745',
1383
- errorColor: '#dc3545',
1384
- warningColor: '#ffc107',
1385
- defaultTextColor: '#212529',
1386
- selectedTextColor: '#ffffff',
1387
- linkTextColor: '#1d4ed8',
1388
- drawerBackgroundColor: '#ffffff',
1389
- buttonCornerRadius: '8px',
1390
- cardCornerRadius: '12px',
1391
- headingFont: {
1392
- name: 'Inter',
1393
- weights: [600, 700]
1394
- },
1395
- paragraphFont: {
1396
- name: 'Inter',
1397
- weights: [400, 500]
1398
- }
1399
- },
1400
- layout: {
1401
- enablePersonalization: true,
1402
- personalizationText: 'Customize your product',
1403
- personalizationCardStyle: 'outlined',
1404
- allowPromoCodes: true,
1405
- inputFieldStyle: 'outlined',
1406
- poweredByMode: 'light'
1407
- }
1408
- }
1409
- }
1410
- });
1411
- ```
1412
-
1413
- ### Component-Specific Theming
1414
-
1415
- #### Product Component
1416
-
1417
- ```js
1418
- customTheme: {
1419
- product: {
1420
- theme: {
1421
- backgroundColor: '#ffffff'
1422
- },
1423
- layout: {
1424
- showImages: true,
1425
- showTitle: true,
1426
- showDescription: true,
1427
- showQuantityCounter: true,
1428
- quantityCounterStyle: 'outlined',
1429
- fulfillmentDisplay: 'carousel',
1430
- enableShippingFulfillment: true,
1431
- enableOnDemandFulfillment: true,
1432
- addToCartButtonText: 'Add to Cart',
1433
- buyNowButtonText: 'Buy Now'
1434
- }
1435
- }
1436
- }
1437
- ```
1438
-
1439
- #### Cart Component
1440
-
1441
- ```js
1442
- customTheme: {
1443
- cart: {
1444
- theme: {
1445
- backgroundColor: '#ffffff'
1446
- },
1447
- layout: {
1448
- showQuantityCounter: true,
1449
- quantityCounterStyle: 'outlined',
1450
- drawerHeaderText: 'Your Cart',
1451
- goToCheckoutButtonText: 'Checkout'
1452
- }
1453
- }
1454
- }
1455
- ```
1456
-
1457
- #### Checkout Component
1458
-
1459
- ```js
1460
- customTheme: {
1461
- checkout: {
1462
- theme: {
1463
- backgroundColor: '#ffffff',
1464
- checkoutCompleted: {
1465
- customLogo: 'https://yourdomain.com/logo.png',
1466
- customText: 'Thank you for your order!'
1467
- }
1468
- },
1469
- layout: {
1470
- emailOptIn: {
1471
- show: true,
1472
- checked: false,
1473
- text: 'Email me with news'
1474
- },
1475
- smsOptIn: {
1476
- show: true,
1477
- checked: false,
1478
- text: 'Text me updates'
1479
- },
1480
- allowGiftCards: true,
1481
- drawerHeaderText: 'Checkout',
1482
- placeOrderButtonText: 'Place Order'
1483
- }
1484
- }
1485
- }
1486
- ```
1487
-
1488
- #### Address Component
1489
-
1490
- ```js
1491
- customTheme: {
1492
- address: {
1493
- theme: {
1494
- backgroundColor: '#ffffff'
1495
- }
1496
- }
1497
- }
1498
- ```
1499
-
1500
- ### Dynamic Theme Updates (Builder Mode)
1501
-
1502
- In development with `isBuilder: true`, update themes in real-time:
1503
-
1504
- ```js
1505
- const client = await Elements('YOUR_API_KEY', {
1506
- env: 'development',
1507
- isBuilder: true
1508
- });
1509
-
1510
- // Update global theme
1511
- await client.builder.updateComponentGlobalConfigs({
1512
- theme: { primaryColor: '#ff6b6b' }
1513
- });
1514
-
1515
- // Update component-specific themes
1516
- await client.builder.updateProductComponent({
1517
- layout: { addToCartButtonText: 'Add to Bag' }
1518
- });
1519
-
1520
- client.builder.updateCartComponent({
1521
- layout: { drawerHeaderText: 'Shopping Bag' }
1522
- });
1523
-
1524
- client.builder.updateCheckoutComponent({
1525
- layout: { placeOrderButtonText: 'Complete Purchase' }
1526
- });
1527
-
1528
- client.builder.updateAddressComponent({
1529
- theme: { backgroundColor: '#f8f9fa' }
1530
- });
1531
- ```
1532
-
1533
- **📖 For complete theming documentation:** See [`docs/THEMING.md`](docs/THEMING.md)
1534
-
1535
- ---
1536
-
1537
- ## 🎁 Features Deep Dive
1538
-
1539
- ### Product Personalization (Engraving)
1540
-
1541
- The SDK provides a comprehensive personalization/engraving feature for products that support it. The personalization experience varies based on context:
1542
-
1543
- #### Product View
1544
- When browsing products, customers can add personalization through an enhanced form that includes:
1545
- - Product information with pricing
1546
- - Fulfillment/retailer selection (with pricing comparison)
1547
- - Multi-line engraving inputs with character limits
1548
- - Real-time price updates as customers select different retailers
1549
- - Add-to-cart with personalization in one step
1550
-
1551
- ```js
1552
- // Personalization appears automatically for engravable products
1553
- // Customers can add engraving text and select which retailer to fulfill from
1554
-
1555
- // Listen for when personalization is added via add-to-cart
1556
- window.addEventListener('lce:actions.product_add_to_cart', (event) => {
1557
- const { hasEngraving, engravingLines } = event.detail.data;
1558
- if (hasEngraving) {
1559
- console.log('Customer personalized:', engravingLines);
1560
- }
1561
- });
1562
- ```
1563
-
1564
- #### Cart View
1565
- In the cart, personalized items display:
1566
- - Personalization text lines
1567
- - Engraving fee (per item and total for quantity)
1568
- - **Edit** button to modify the personalization
1569
- - **Remove** button to remove personalization
1570
-
1571
- ```js
1572
- // Customers can edit or remove engraving from cart items
1573
- window.addEventListener('lce:actions.cart_item_engraving_updated', (event) => {
1574
- const { identifier, engravingLines } = event.detail.data;
1575
- console.log('Cart item engraving updated:', engravingLines);
1576
- });
1577
- ```
1578
-
1579
- #### Checkout View
1580
- During checkout, personalized items show:
1581
- - Personalization text lines (read-only)
1582
- - Engraving fee included in pricing
1583
- - **Remove** button only (editing not allowed in checkout)
1584
-
1585
- **Design Decision:** Editing personalization during checkout is intentionally disabled to prevent order processing complications. Customers must return to the cart to make changes.
1586
-
1587
- #### Theming & Configuration
1588
-
1589
- Control personalization display through global configuration:
1590
-
1591
- ```js
1592
- customTheme: {
1593
- global: {
1594
- layout: {
1595
- enablePersonalization: true,
1596
- personalizationText: 'Personalize your product',
1597
- personalizationCardStyle: 'outlined' // or 'filled'
1598
- }
1599
- }
1600
- }
1601
- ```
1602
-
1603
- #### Key Features
1604
- - **Smart pricing:** Automatically includes engraving fees in product price
1605
- - **Retailer selection:** Compare prices from different retailers during personalization
1606
- - **Character limits:** Enforces maximum characters per line
1607
- - **Uppercase conversion:** Engraving text is automatically converted to uppercase
1608
- - **Multi-line support:** Products can support 1 or more engraving lines
1609
- - **Fee transparency:** Shows per-item and total fees (e.g., "$5.00 ($2.50 ea)")
1610
-
1611
- **Note:** Personalization is automatically enabled for products that support it. The SDK handles all UI, validation, and state management.
1612
-
1613
- ### Gift Options
1614
-
1615
- Allow orders to be marked as gifts with custom messages:
1616
-
1617
- ```js
1618
- // Enable via theme
1619
- customTheme: {
1620
- checkout: {
1621
- layout: {
1622
- allowGiftOptions: true
1623
- }
1624
- }
1625
- }
1626
-
1627
- // Toggle gift mode programmatically
1628
- await client.actions.checkout.toggleIsGift(true);
1629
-
1630
- // Set gift message
1631
- await client.actions.checkout.updateGiftInfo({
1632
- recipientName: 'John Doe',
1633
- message: 'Happy Birthday!'
1634
- });
1635
-
1636
- // Listen for gift toggles
1637
- window.addEventListener('lce:actions.checkout_is_gift_toggled', (event) => {
1638
- const { isGift } = event.detail.data;
1639
- console.log('Order is gift:', isGift);
1640
- });
1641
- ```
1642
-
1643
- ### Tips (On-Demand Delivery)
1644
-
1645
- Allow customers to tip delivery drivers:
1646
-
1647
- ```js
1648
- // Tips are automatically enabled for onDemand fulfillment types
1649
-
1650
- // Listen for tip updates
1651
- window.addEventListener('lce:actions.checkout_tip_updated', (event) => {
1652
- const { tipAmount, total } = event.detail.data;
1653
- console.log(`Customer tipped $${tipAmount}`);
1654
- });
1655
- ```
1656
-
1657
- Tips are calculated as a percentage or fixed amount and added to the order total.
1658
-
1659
- ### Gift Cards
1660
-
1661
- Accept gift card payments at checkout:
1662
-
1663
- ```js
1664
- // Enable via theme
1665
- customTheme: {
1666
- checkout: {
1667
- layout: {
1668
- allowGiftCards: true
1669
- }
1670
- }
1671
- }
1672
-
1673
- // Apply gift card programmatically
1674
- await client.actions.checkout.applyGiftCard('GIFT-1234-5678-9012');
1675
-
1676
- // Remove gift card
1677
- await client.actions.checkout.removeGiftCard('GIFT-1234-5678-9012');
1678
-
1679
- // Listen for gift card events
1680
- window.addEventListener('lce:actions.checkout_gift_card_applied', (event) => {
1681
- const { newTotal } = event.detail.data;
1682
- console.log(`Gift card applied! New total: $${newTotal}`);
1683
- });
1684
-
1685
- window.addEventListener('lce:actions.checkout_gift_card_failed', (event) => {
1686
- const { error } = event.detail.data;
1687
- console.log('Gift card failed:', error);
1688
- });
1689
- ```
1690
-
1691
- ### Promo Codes
1692
-
1693
- Apply promotional discount codes:
1694
-
1695
- ```js
1696
- // Apply to cart
1697
- await client.actions.cart.applyPromoCode('SUMMER20');
1698
-
1699
- // Apply to checkout
1700
- await client.actions.checkout.applyPromoCode('SAVE10');
1701
-
1702
- // Remove promo code
1703
- await client.actions.cart.removePromoCode();
1704
-
1705
- // Listen for promo events
1706
- window.addEventListener('lce:actions.cart_promo_code_applied', (event) => {
1707
- const { discount, newTotal } = event.detail.data;
1708
- console.log(`Promo applied! Saved $${discount}! New total: $${newTotal}`);
1709
- });
1710
-
1711
- window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
1712
- const { error } = event.detail.data;
1713
- console.log('Promo failed:', error);
1714
- });
1715
- ```
1716
-
1717
- ### Promo Ticker
1718
-
1719
- Display rotating promotional messages at the top of your site:
1720
-
1721
- ```js
1722
- // Via initialization config
1723
- const client = await Elements('YOUR_API_KEY', {
1724
- promoTicker: [
1725
- {
1726
- promoCode: 'FREESHIP',
1727
- text: ['Free Shipping Today!', 'Use code FREESHIP'],
1728
- separator: '•',
1729
- activeFrom: '2025-01-01T00:00:00Z',
1730
- activeUntil: '2025-12-31T23:59:59Z'
1731
- },
1732
- {
1733
- promoCode: 'SAVE20',
1734
- text: ['20% Off Sitewide', 'Limited Time Only'],
1735
- separator: '|',
1736
- activeFrom: '2025-06-01T00:00:00Z',
1737
- activeUntil: '2025-06-30T23:59:59Z'
1738
- }
1739
- ]
1740
- });
1741
-
1742
- // Via auto-init
1743
- <script
1744
- data-liquid-commerce-elements
1745
- data-token="YOUR_API_KEY"
1746
- data-promo-code="FREESHIP"
1747
- data-promo-text="Free Shipping Today!|Use code FREESHIP"
1748
- data-promo-separator="•"
1749
- data-promo-active-from="2025-01-01T00:00:00Z"
1750
- data-promo-active-until="2025-12-31T23:59:59Z"
1751
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
1752
- ></script>
1753
- ```
1754
-
1755
- The ticker automatically rotates messages and only shows active promotions.
1756
-
1757
- ### Marketing Preferences
1758
-
1759
- Allow customers to opt-in to email and SMS marketing:
1760
-
1761
- ```js
1762
- // Set defaults via theme
1763
- customTheme: {
1764
- checkout: {
1765
- layout: {
1766
- emailOptIn: { checked: false, visible: true },
1767
- smsOptIn: { checked: false, visible: true }
1768
- }
1769
- }
1770
- }
1771
-
1772
- // Update preferences programmatically
1773
- await client.actions.checkout.toggleMarketingPreferences('canEmail', true);
1774
- await client.actions.checkout.toggleMarketingPreferences('canSms', true);
1775
-
1776
- // Listen for preference changes
1777
- window.addEventListener('lce:actions.checkout_marketing_preferences_toggled', (event) => {
1778
- const { field, value } = event.detail.data;
1779
- console.log(`Customer ${value ? 'opted-in' : 'opted-out'} of ${field}`);
1780
- });
1781
- ```
1782
-
1783
- ### Purchase Minimum Alerts
1784
-
1785
- Automatically displays alerts when a retailer has minimum purchase requirements. No configuration needed - the SDK handles this automatically based on retailer rules.
1786
-
1787
- ### Age Verification
1788
-
1789
- For age-restricted products (alcohol, tobacco, etc.), the SDK automatically displays age verification prompts during checkout. This is handled based on product metadata and cannot be disabled for restricted items.
1790
-
1791
- ### Pre-Sale Countdown
1792
-
1793
- For pre-sale or upcoming products, the SDK automatically displays a countdown timer until the product becomes available. Customers can add pre-sale items to cart, and the SDK handles the special fulfillment flow.
1794
-
1795
- ```js
1796
- // Listen for when product is added to cart
1797
- window.addEventListener('lce:actions.product_add_to_cart', (event) => {
1798
- const { productId } = event.detail.data;
1799
- console.log(`Product ${productId} added to cart`);
1800
- });
1801
- ```
1802
-
1803
- ### Product List
1804
-
1805
- Display a filtered, paginated product catalog with infinite scroll. Perfect for category pages, catalog pages, and search results.
1806
-
1807
- #### Auto-Initialization
1808
-
1809
- Add a product list to any page with data attributes:
1810
-
1811
- ```html
1812
- <div data-liquid-commerce-elements-products-list
1813
- data-rows="3"
1814
- data-columns="4"
1815
- data-filters="engraving,presale,fulfillment,price,brands"
1816
- data-product-url="/product/{upc}">
1817
- </div>
1818
- ```
1819
-
1820
- You can also add separate search and filter containers:
1821
-
1822
- ```html
1823
- <!-- Search bar -->
1824
- <div data-search-container></div>
1825
-
1826
- <!-- Sidebar filters -->
1827
- <div data-filters-container></div>
1828
-
1829
- <!-- Product grid -->
1830
- <div data-liquid-commerce-elements-products-list
1831
- data-rows="4"
1832
- data-columns="4"
1833
- data-filters="price,brands,categories,variety"
1834
- data-product-url="/product/{upc}">
1835
- </div>
1836
- ```
1837
-
1838
- #### Programmatic Injection
1839
-
1840
- ```js
1841
- await client.injectProductList({
1842
- containerId: 'product-list-container',
1843
- rows: 3,
1844
- columns: 4,
1845
- filters: ['engraving', 'presale', 'fulfillment', 'price', 'brands'],
1846
- productUrl: '/product/{upc}'
1847
- });
1848
-
1849
- // Optional: inject search and filters in separate containers
1850
- await client.injectProductListSearch({
1851
- containerId: 'search-container'
1852
- });
1853
-
1854
- await client.injectProductListFilters({
1855
- containerId: 'filters-sidebar',
1856
- filters: ['price', 'brands', 'categories', 'variety']
1857
- });
1858
- ```
1859
-
1860
- #### Features
1861
-
1862
- **Filtering (14 filter types):**
1863
- - **engraving** - Show only products that support engraving/personalization
1864
- - **presale** - Show only pre-order products
1865
- - **fulfillment** - Filter by delivery type (shipping, onDemand)
1866
- - **price** - Filter by price range
1867
- - **brands** - Filter by brand
1868
- - **categories** - Filter by category
1869
- - **flavor** - Filter by flavor profile
1870
- - **region** - Filter by region
1871
- - **variety** - Filter by variety (e.g., Cabernet Sauvignon)
1872
- - **vintage** - Filter by vintage year
1873
- - **country** - Filter by country of origin
1874
- - **appellation** - Filter by appellation
1875
- - **materials** - Filter by material type
1876
- - **sizes** - Filter by product size
1877
-
1878
- **Smart Filter Logic:**
1879
- - When "Same-Day Delivery" is selected, engraving and presale filters are automatically disabled
1880
- - When engraving or presale is enabled, same-day delivery is automatically disabled
1881
- - Filters work together intelligently to show only compatible product combinations
1882
-
1883
- **Infinite Scroll:**
1884
- - Automatically loads more products as you scroll
1885
- - Shows loading states during pagination
1886
- - Handles "no more products" gracefully
1887
-
1888
- **Address-Aware:**
1889
- - Automatically reloads when address changes
1890
- - Shows availability based on current location
1891
- - Updates product pricing and fulfillment options dynamically
1892
-
1893
- **Product Cards:**
1894
- - Display product image, name, size, and price
1895
- - Show availability status based on location
1896
- - "Add to Cart" button (disabled if unavailable)
1897
- - Clickable product links (if `productUrl` is provided)
1898
- - Presale product support with special handling
1899
-
1900
- **Analytics Tracking:**
1901
- - Automatically tracks `view_item_list` when products load
1902
- - Tracks `select_item` when user clicks a product link
1903
- - GTM integration for e-commerce events
1904
-
1905
- **Loading States:**
1906
- - Shows skeleton loading cards during initial load
1907
- - Displays loading indicator during infinite scroll
1908
- - Error handling with user-friendly messages
1909
-
1910
- **Product URL Templates:**
1911
- - Use `{upc}` placeholder for UPC-based URLs: `/product/{upc}`
1912
- - Use `{grouping}` placeholder for Salsify grouping IDs: `/product/{grouping}`
1913
- - Links open in new tab with proper security attributes
1914
-
1915
- #### Example: Category Page
1916
-
1917
- ```html
1918
- <div id="category-products"
1919
- data-liquid-commerce-elements-products-list
1920
- data-rows="4"
1921
- data-columns="4"
1922
- data-filters="engraving,fulfillment,price,brands"
1923
- data-product-url="/products/{upc}">
1924
- </div>
1925
-
1926
- <script
1927
- data-liquid-commerce-elements
1928
- data-token="YOUR_API_KEY"
1929
- data-env="production"
1930
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
1931
- ></script>
1932
- ```
1933
-
1934
- #### Example: Search Results with Sidebar Filters
1935
-
1936
- ```js
1937
- const client = await Elements('YOUR_API_KEY', {
1938
- env: 'production'
1939
- });
1940
-
1941
- // Inject search bar
1942
- await client.injectProductListSearch({
1943
- containerId: 'search-bar'
1944
- });
1945
-
1946
- // Inject product grid
1947
- await client.injectProductList({
1948
- containerId: 'search-results',
1949
- rows: 6,
1950
- columns: 3,
1951
- filters: ['fulfillment', 'price', 'brands', 'categories'],
1952
- productUrl: '/search?q={grouping}'
1953
- });
1954
-
1955
- // Inject sidebar filters
1956
- await client.injectProductListFilters({
1957
- containerId: 'filters-sidebar',
1958
- filters: ['price', 'brands', 'categories', 'variety']
1959
- });
1960
- ```
1961
-
1962
- **Use cases:**
1963
- - Category pages
1964
- - Catalog pages
1965
- - Search results
1966
- - Filtered product browsing
1967
- - Personalized product recommendations
1968
- - Pre-order product showcases
1969
-
1970
- ---
1971
-
1972
- ## 🔧 Core Capabilities
1973
-
1974
- The SDK includes several built-in services that work behind the scenes to provide a robust, production-ready experience.
1975
-
1976
- ### State Management
1977
-
1978
- The SDK uses a centralized store for all state management. Access state data via actions:
1979
-
1980
- ```js
1981
- // Get current cart state
1982
- const cart = await client.actions.cart.getDetails();
1983
- console.log(cart.itemCount, cart.amounts.total, cart.amounts.giftCardTotal);
1984
-
1985
- // Get current checkout state
1986
- const checkout = await client.actions.checkout.getDetails();
1987
- console.log(checkout.amounts.total, checkout.isGift, checkout.acceptedAccountCreation);
1988
- console.log(checkout.billingSameAsShipping, checkout.marketingPreferences);
1989
-
1990
- // Get current address
1991
- const address = await client.actions.address.getDetails();
1992
- console.log(address.formattedAddress, address.coordinates);
1993
-
1994
- // Get product details
1995
- const product = await client.actions.product.getDetails('00619947000020');
1996
- console.log(product.name, product.region, product.variety, product.vintage);
1997
- console.log(product.description, product.tastingNotes);
1998
- ```
1999
-
2000
- **State is persistent:** Cart and address data persist across page reloads using localStorage.
2001
-
2002
- ### Event System (PubSub)
2003
-
2004
- All SDK interactions emit events through a centralized event system:
2005
-
2006
- ```js
2007
- // Subscribe to specific event
2008
- window.addEventListener('lce:actions.cart_updated', (event) => {
2009
- const { previous, current } = event.detail.data;
2010
- console.log('Cart changed from', previous.amounts.total, 'to', current.amounts.total);
2011
- });
2012
-
2013
- // Subscribe to all action events
2014
- if (window.elements) {
2015
- window.elements.onAllActions((data, metadata) => {
2016
- console.log('Action:', metadata.eventName, data);
2017
- });
2018
- }
2019
-
2020
- // Subscribe to all form events
2021
- if (window.elements) {
2022
- window.elements.onAllForms((data, metadata) => {
2023
- console.log('Form:', metadata.eventName, data);
2024
- });
2025
- }
2026
- ```
2027
-
2028
- **Event format:**
2029
- ```js
2030
- {
2031
- detail: {
2032
- data: { /* event-specific payload */ },
2033
- metadata: {
2034
- eventName: 'lce:actions.cart_updated',
2035
- timestamp: 1699564800000,
2036
- source: 'sdk'
2037
- }
2038
- }
2039
- }
2040
- ```
2041
-
2042
- ### Telemetry & Analytics
2043
-
2044
- The SDK automatically tracks user interactions and performance metrics:
2045
-
2046
- - **User interactions:** Add to cart, checkout started, checkout completed
2047
- - **Performance metrics:** Component load times, API response times
2048
- - **Error tracking:** Failed API calls, validation errors
2049
-
2050
- **Note:** The SDK includes automatic Google Tag Manager (GTM) integration that tracks e-commerce events. GTM configuration is managed through your LiquidCommerce dashboard, not the client initialization.
2051
-
2052
- **Custom Analytics:**
2053
-
2054
- ```js
2055
- // Listen to events for custom analytics tracking
2056
- window.addEventListener('lce:actions.product_add_to_cart', (event) => {
2057
- const { productId, price, quantity } = event.detail.data;
2058
-
2059
- // Track with your analytics provider
2060
- gtag('event', 'add_to_cart', {
2061
- currency: 'USD',
2062
- value: price * quantity,
2063
- items: [{ item_id: productId, quantity }]
2064
- });
2065
-
2066
- // Or Segment
2067
- analytics.track('Product Added', {
2068
- product_id: productId,
2069
- price,
2070
- quantity
2071
- });
2072
- });
2073
- ```
2074
-
2075
- ### Fingerprinting
2076
-
2077
- The SDK generates a unique device fingerprint for fraud prevention and analytics:
2078
-
2079
- ```js
2080
- // Automatically tracked:
2081
- // - Browser fingerprint
2082
- // - Device characteristics
2083
- // - Session information
2084
-
2085
- // Used for:
2086
- // - Fraud detection
2087
- // - Cart persistence across devices
2088
- // - Personalization
2089
- ```
2090
-
2091
- Fingerprinting is handled automatically and requires no configuration.
2092
-
2093
- ### Authentication
2094
-
2095
- The SDK handles authentication automatically using your API key:
2096
-
2097
- ```js
2098
- const client = await Elements('YOUR_API_KEY', {
2099
- env: 'production'
2100
- });
2101
-
2102
- // All API requests include:
2103
- // - API key authentication
2104
- // - CORS headers
2105
- // - Request signing (when required)
2106
- ```
2107
-
2108
- **Token refresh:** The SDK automatically handles token expiration and refresh.
2109
-
2110
- ### Logger
2111
-
2112
- Built-in logging system with configurable levels:
2113
-
2114
- ```js
2115
- const client = await Elements('YOUR_API_KEY', {
2116
- debugMode: 'console' // 'none' | 'console' | 'panel'
2117
- });
2118
-
2119
- // Debug mode options:
2120
- // - 'none': No logging (production default)
2121
- // - 'console': Logs to browser console
2122
- // - 'panel': Shows visual debug panel + console logs
2123
- ```
2124
-
2125
- **Console debug output:**
2126
- ```
2127
- [LCE SDK] Product loaded: product-123
2128
- [LCE SDK] Cart updated: 3 items, $45.99
2129
- [LCE SDK] Checkout started
2130
- [LCE SDK] API call: POST /cart/add (152ms)
2131
- ```
2132
-
2133
- **Debug panel:**
2134
- - Real-time event stream
2135
- - API call inspector
2136
- - State viewer
2137
- - Performance metrics
2138
-
2139
- ### Command Pattern
2140
-
2141
- The SDK uses a command pattern for all operations:
2142
-
2143
- ```js
2144
- // Commands are:
2145
- // - Queued for execution
2146
- // - Retried on failure
2147
- // - Logged for debugging
2148
- // - Cancelable
2149
-
2150
- // Example: Adding to cart
2151
- // 1. Command created: AddToCartCommand
2152
- // 2. Command queued
2153
- // 3. Command executed
2154
- // 4. Success event emitted
2155
- // 5. UI updated
2156
-
2157
- // This ensures:
2158
- // - Consistent error handling
2159
- // - Automatic retries
2160
- // - Full audit trail
2161
- ```
2162
-
2163
- ### Component Factory
2164
-
2165
- Components are created on-demand using a factory pattern:
2166
-
2167
- ```js
2168
- // When you call:
2169
- const components = await client.injectProductElement([
2170
- { containerId: 'pdp-1', identifier: 'product-123' }
2171
- ]);
2172
- // Returns: IInjectedComponent[] - Array of component wrappers
2173
-
2174
- // The SDK:
2175
- // 1. Creates a ProductComponent instance
2176
- // 2. Registers it with the factory
2177
- // 3. Injects it into the DOM
2178
- // 4. Attaches event listeners
2179
- // 5. Loads product data
2180
- // 6. Renders the component
2181
-
2182
- // Components are:
2183
- // - Lazily loaded
2184
- // - Automatically cleaned up
2185
- // - Reusable across pages
2186
- ```
2187
-
2188
- ### Singleton Manager
2189
-
2190
- Core services are managed as singletons:
12
+ [![Zero Dependencies](https://img.shields.io/badge/Dependencies-Zero-brightgreen)](./package.json)
13
+ [![Browser Support](https://img.shields.io/badge/Browsers-2018+-4285F4?logo=googlechrome&logoColor=white)](./docs/v1/reference/browser-support.md)
2191
14
 
2192
- ```js
2193
- // These services are initialized once and reused:
2194
- // - ApiClient
2195
- // - Store
2196
- // - PubSub
2197
- // - Logger
2198
- // - Telemetry
2199
- // - Fingerprint
2200
- // - Auth
15
+ **Add product displays, shopping carts, and checkout flows to any website**
2201
16
 
2202
- // This ensures:
2203
- // - Consistent state
2204
- // - Efficient memory usage
2205
- // - No duplicate API calls
2206
- ```
17
+ </div>
2207
18
 
2208
19
  ---
2209
20
 
2210
- ## 🏗️ Integration Patterns
2211
-
2212
- ### React Integration
2213
-
2214
- ```jsx
2215
- import { useEffect, useState } from 'react';
2216
- import { Elements } from '@liquidcommerce/elements-sdk';
2217
-
2218
- function ProductPage({ productId }) {
2219
- const [client, setClient] = useState(null);
2220
-
2221
- useEffect(() => {
2222
- async function initSDK() {
2223
- const elementsClient = await Elements(process.env.REACT_APP_LCE_API_KEY, {
2224
- env: 'production'
2225
- });
2226
- setClient(elementsClient);
2227
-
2228
- // Inject product
2229
- await elementsClient.injectProductElement([
2230
- { containerId: 'product-container', identifier: productId }
2231
- ]);
2232
-
2233
- // Create cart button
2234
- elementsClient.ui.cartButton('cart-button', true);
2235
- }
2236
-
2237
- initSDK();
2238
-
2239
- // Cleanup
2240
- return () => {
2241
- // SDK handles cleanup automatically
2242
- };
2243
- }, [productId]);
2244
-
2245
- return (
2246
- <div>
2247
- <div id="cart-button"></div>
2248
- <div id="product-container"></div>
2249
- </div>
2250
- );
2251
- }
2252
- ```
2253
-
2254
- ### Vue Integration
2255
-
2256
- ```vue
2257
- <template>
2258
- <div>
2259
- <div ref="cartButton"></div>
2260
- <div ref="productContainer"></div>
2261
- </div>
2262
- </template>
2263
-
2264
- <script>
2265
- import { Elements } from '@liquidcommerce/elements-sdk';
2266
-
2267
- export default {
2268
- name: 'ProductPage',
2269
- props: ['productId'],
2270
- async mounted() {
2271
- this.client = await Elements(process.env.VUE_APP_LCE_API_KEY, {
2272
- env: 'production'
2273
- });
2274
-
2275
- await this.client.injectProductElement([
2276
- { containerId: this.$refs.productContainer.id, identifier: this.productId }
2277
- ]);
2278
-
2279
- this.client.ui.cartButton(this.$refs.cartButton.id, true);
2280
- }
2281
- }
2282
- </script>
2283
- ```
2284
-
2285
- ### Next.js Integration
2286
-
2287
- ```tsx
2288
- 'use client';
2289
-
2290
- import { useEffect } from 'react';
2291
-
2292
- export default function ProductPage({ productId }: { productId: string }) {
2293
- useEffect(() => {
2294
- // Load SDK script
2295
- const script = document.createElement('script');
2296
- script.src = 'https://assets-elements.liquidcommerce.us/all/elements.js';
2297
- script.async = true;
2298
- script.onload = async () => {
2299
- const client = await (window as any).Elements(process.env.NEXT_PUBLIC_LCE_API_KEY, {
2300
- env: 'production'
2301
- });
2302
-
2303
- const components = await client.injectProductElement([
2304
- { containerId: 'product-container', identifier: productId }
2305
- ]);
2306
-
2307
- client.ui.floatingCartButton(true);
2308
- };
2309
- document.body.appendChild(script);
21
+ ## Overview
2310
22
 
2311
- return () => {
2312
- document.body.removeChild(script);
2313
- };
2314
- }, [productId]);
23
+ Elements SDK is a Web Components-based e-commerce SDK that lets you add product displays, a cart, and checkout to any site with minimal code. It’s framework-agnostic, fully themeable, and works via CDN or NPM.
2315
24
 
2316
- return <div id="product-container"></div>;
2317
- }
2318
- ```
2319
-
2320
- ### WordPress Integration
25
+ ## What You Can Build
2321
26
 
2322
- ```html
2323
- <!-- In your theme's header.php or functions.php -->
2324
- <script
2325
- data-liquid-commerce-elements
2326
- data-token="<?php echo get_option('lce_api_key'); ?>"
2327
- data-env="production"
2328
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
2329
- ></script>
27
+ - Product pages with variants, fulfillment options, and add-to-cart
28
+ - Cart drawer with promo codes and totals
29
+ - Checkout drawer or hosted checkout page
30
+ - Multi-product grids and searchable lists
31
+ - Address capture for delivery availability and pricing
2330
32
 
2331
- <!-- In your product template -->
2332
- <div data-lce-product="<?php echo get_post_meta(get_the_ID(), 'product_upc', true); ?>"></div>
2333
- ```
33
+ ## Installation
2334
34
 
2335
- ### Shopify Integration
35
+ ### CDN (Fastest)
2336
36
 
2337
37
  ```html
2338
- <!-- In theme.liquid -->
2339
38
  <script
39
+ defer
2340
40
  data-liquid-commerce-elements
2341
- data-token="{{ settings.lce_api_key }}"
41
+ data-token="YOUR_API_KEY"
2342
42
  data-env="production"
43
+ data-container-1="product"
44
+ data-product-1="00619947000020"
45
+ type="text/javascript"
2343
46
  src="https://assets-elements.liquidcommerce.us/all/elements.js"
2344
47
  ></script>
2345
48
 
2346
- <!-- In product template -->
2347
- <div data-lce-product="{{ product.barcode }}"></div>
2348
- ```
2349
-
2350
- ### Multi-Page Applications
2351
-
2352
- For SPAs and multi-page apps, initialize once and reuse:
2353
-
2354
- ```js
2355
- // app.js (initialize once)
2356
- let elementsClient = null;
2357
-
2358
- async function getElementsClient() {
2359
- if (!elementsClient) {
2360
- elementsClient = await Elements('YOUR_API_KEY', {
2361
- env: 'production'
2362
- });
2363
- }
2364
- return elementsClient;
2365
- }
2366
-
2367
- // product-page.js
2368
- const client = await getElementsClient();
2369
- await client.injectProductElement([
2370
- { containerId: 'pdp-1', identifier: productId }
2371
- ]);
2372
-
2373
- // cart-page.js
2374
- const client = await getElementsClient();
2375
- const cartComponent = await client.injectCartElement('cart-container');
2376
- ```
2377
-
2378
- ---
2379
-
2380
- ## 🚨 Error Handling
2381
-
2382
- ### Initialization Errors
2383
-
2384
- ```js
2385
- try {
2386
- const client = await Elements('YOUR_API_KEY', {
2387
- env: 'production'
2388
- });
2389
- } catch (error) {
2390
- if (error.message.includes('Invalid API key')) {
2391
- console.error('Authentication failed');
2392
- } else if (error.message.includes('Network')) {
2393
- console.error('Network error - check connectivity');
2394
- } else {
2395
- console.error('SDK initialization failed:', error);
2396
- }
2397
- }
2398
- ```
2399
-
2400
- ### Action Errors
2401
-
2402
- All actions emit failure events with detailed error information:
2403
-
2404
- ```js
2405
- // Product loaded successfully
2406
- window.addEventListener('lce:actions.product_loaded', (event) => {
2407
- const { identifier, productData } = event.detail.data;
2408
- console.log(`Product ${identifier} loaded successfully`);
2409
- });
2410
-
2411
- // Cart action failure
2412
- window.addEventListener('lce:actions.cart_product_add_failed', (event) => {
2413
- const { identifiers, error } = event.detail.data;
2414
- console.error('Failed to add products:', error);
2415
-
2416
- // Show user-friendly message
2417
- showNotification('Could not add to cart. Please try again.', 'error');
2418
- });
2419
-
2420
- // Checkout failure
2421
- window.addEventListener('lce:actions.checkout_submit_failed', (event) => {
2422
- const { error, reason } = event.detail.data;
2423
- console.error('Checkout failed:', reason);
2424
-
2425
- // Handle specific errors
2426
- if (reason.includes('payment')) {
2427
- showNotification('Payment declined. Please check your card details.', 'error');
2428
- } else if (reason.includes('inventory')) {
2429
- showNotification('Some items are no longer available.', 'warning');
2430
- } else {
2431
- showNotification('Checkout failed. Please try again.', 'error');
2432
- }
2433
- });
2434
-
2435
- // Address validation failure
2436
- window.addEventListener('lce:actions.address_failed', (event) => {
2437
- const { error } = event.detail.data;
2438
- console.error('Address validation failed:', error);
2439
- showNotification('Please enter a valid address.', 'error');
2440
- });
2441
-
2442
- // Promo code failure
2443
- window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
2444
- const { code, error } = event.detail.data;
2445
- console.error(`Promo code ${code} failed:`, error);
2446
-
2447
- if (error.includes('expired')) {
2448
- showNotification('This promo code has expired.', 'warning');
2449
- } else if (error.includes('invalid')) {
2450
- showNotification('Invalid promo code.', 'error');
2451
- } else if (error.includes('minimum')) {
2452
- showNotification('Cart minimum not met for this promo.', 'warning');
2453
- }
2454
- });
2455
- ```
2456
-
2457
- ### Network Error Recovery
2458
-
2459
- ```js
2460
- let retryCount = 0;
2461
- const maxRetries = 3;
2462
-
2463
- async function addProductWithRetry(productParams) {
2464
- try {
2465
- await client.actions.cart.addProduct(productParams);
2466
- } catch (error) {
2467
- if (retryCount < maxRetries && error.message.includes('Network')) {
2468
- retryCount++;
2469
- console.log(`Retrying... Attempt ${retryCount}/${maxRetries}`);
2470
- setTimeout(() => addProductWithRetry(productParams), 1000 * retryCount);
2471
- } else {
2472
- console.error('Failed after retries:', error);
2473
- showNotification('Network error. Please check your connection.', 'error');
2474
- }
2475
- }
2476
- }
2477
- ```
2478
-
2479
- ### Global Error Handler
2480
-
2481
- ```js
2482
- // Listen to all failed events
2483
- window.addEventListener('lce:actions.cart_failed', handleError);
2484
- window.addEventListener('lce:actions.checkout_failed', handleError);
2485
- window.addEventListener('lce:actions.address_failed', handleError);
2486
- window.addEventListener('lce:actions.cart_product_add_failed', handleError);
2487
-
2488
- function handleError(event) {
2489
- const { error, context } = event.detail.data;
2490
-
2491
- // Log to error tracking service
2492
- if (window.Sentry) {
2493
- Sentry.captureException(error, {
2494
- tags: { sdk: 'liquid-commerce' },
2495
- extra: context
2496
- });
2497
- }
2498
-
2499
- // Show user notification
2500
- showNotification('Something went wrong. Please try again.', 'error');
2501
- }
2502
- ```
2503
-
2504
- ---
2505
-
2506
- ## ⚡ Performance & Best Practices
2507
-
2508
- ### Lazy Loading Components
2509
-
2510
- Only inject components when needed:
2511
-
2512
- ```js
2513
- // ❌ Don't inject all components upfront
2514
- await client.injectProductElement([/* 50 products */]);
2515
- await client.injectCartElement('cart');
2516
- await client.injectCheckoutElement({ containerId: 'checkout' });
2517
-
2518
- // ✅ Inject components as user navigates
2519
- // On product page:
2520
- await client.injectProductElement([{ containerId: 'pdp', identifier: productId }]);
2521
-
2522
- // On cart page (when user clicks cart):
2523
- await client.injectCartElement('cart');
2524
-
2525
- // On checkout (when user proceeds):
2526
- await client.injectCheckoutElement({ containerId: 'checkout' });
49
+ <div id="product"></div>
2527
50
  ```
2528
51
 
2529
- ### Reuse Client Instance
2530
-
2531
- Initialize once, use everywhere:
2532
-
2533
- ```js
2534
- // ❌ Don't create multiple clients
2535
- // page1.js
2536
- const client1 = await Elements('KEY', { env: 'production' });
2537
- // page2.js
2538
- const client2 = await Elements('KEY', { env: 'production' });
2539
-
2540
- // ✅ Create once, reuse
2541
- // app.js
2542
- window.lceClient = await Elements('KEY', { env: 'production' });
52
+ ### NPM (Programmatic)
2543
53
 
2544
- // page1.js
2545
- const client = window.lceClient;
2546
- await client.injectProductElement([...]);
2547
-
2548
- // page2.js
2549
- const client = window.lceClient;
2550
- await client.injectCartElement('cart');
54
+ ```bash
55
+ npm install @liquidcommerce/elements-sdk
2551
56
  ```
2552
57
 
2553
- ### Batch Product Injections
2554
-
2555
- Group product injections together:
2556
-
2557
- ```js
2558
- // ❌ Don't inject products one by one
2559
- await client.injectProductElement([{ containerId: 'p1', identifier: 'id1' }]);
2560
- await client.injectProductElement([{ containerId: 'p2', identifier: 'id2' }]);
2561
- await client.injectProductElement([{ containerId: 'p3', identifier: 'id3' }]);
58
+ ```javascript
59
+ import { Elements } from '@liquidcommerce/elements-sdk';
2562
60
 
2563
- // Inject all products at once
61
+ const client = await Elements('YOUR_API_KEY', { env: 'production' });
2564
62
  await client.injectProductElement([
2565
- { containerId: 'p1', identifier: 'id1' },
2566
- { containerId: 'p2', identifier: 'id2' },
2567
- { containerId: 'p3', identifier: 'id3' }
63
+ { containerId: 'product', identifier: '00619947000020' }
2568
64
  ]);
2569
65
  ```
2570
66
 
2571
- ### Optimize Event Listeners
2572
-
2573
- Use event delegation instead of multiple listeners:
2574
-
2575
- ```js
2576
- // ❌ Don't listen to every event
2577
- window.addEventListener('lce:actions.product_loaded', handler);
2578
- window.addEventListener('lce:actions.product_add_to_cart', handler);
2579
- window.addEventListener('lce:actions.cart_updated', handler);
2580
- // ... 20 more listeners
2581
-
2582
- // ✅ Use consolidated listeners
2583
- window.elements.onAllActions((data, metadata) => {
2584
- switch (metadata.eventName) {
2585
- case 'lce:actions.product_loaded':
2586
- handleProductLoad(data);
2587
- break;
2588
- case 'lce:actions.product_add_to_cart':
2589
- handleAddToCart(data);
2590
- break;
2591
- case 'lce:actions.cart_updated':
2592
- handleCartUpdate(data);
2593
- break;
2594
- }
2595
- });
2596
- ```
2597
-
2598
- ### Defer Non-Critical Operations
2599
-
2600
- Load SDK after critical page content:
2601
-
2602
- ```html
2603
- <!-- ❌ Don't load SDK in <head> -->
2604
- <head>
2605
- <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
2606
- </head>
2607
-
2608
- <!-- ✅ Load SDK with defer or at end of body -->
2609
- <head>
2610
- <script defer src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
2611
- </head>
2612
-
2613
- <!-- Or -->
2614
- <body>
2615
- <!-- Your page content -->
2616
- <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
2617
- </body>
2618
- ```
2619
-
2620
- ### Use Auto-Init for Simple Cases
2621
-
2622
- Auto-init is optimized for performance:
2623
-
2624
- ```html
2625
- <!-- ✅ Auto-init is the fastest way for simple setups -->
2626
- <div data-lce-product="00619947000020"></div>
2627
- <div data-lce-product="00832889005513"></div>
2628
-
2629
- <script
2630
- data-liquid-commerce-elements
2631
- data-token="YOUR_API_KEY"
2632
- data-env="production"
2633
- src="https://assets-elements.liquidcommerce.us/all/elements.js"
2634
- ></script>
2635
- ```
2636
-
2637
- ### Avoid Unnecessary Re-renders
2638
-
2639
- Don't repeatedly inject the same component:
2640
-
2641
- ```js
2642
- // ❌ Don't re-inject on every state change
2643
- function updateProduct() {
2644
- setProductId(newId);
2645
- await client.injectProductElement([{ containerId: 'pdp', identifier: newId }]);
2646
- }
2647
-
2648
- // ✅ Components update automatically on state changes
2649
- // Just inject once
2650
- useEffect(() => {
2651
- client.injectProductElement([{ containerId: 'pdp', identifier: productId }]);
2652
- }, []); // Empty deps - inject once
2653
-
2654
- // Product will auto-update when you call actions
2655
- await client.actions.cart.addProduct([...]);
2656
- ```
2657
-
2658
- ### Cache Frequently Accessed Data
2659
-
2660
- ```js
2661
- // ❌ Don't repeatedly fetch the same data
2662
- async function showCartTotal() {
2663
- const cart = await client.actions.cart.getDetails();
2664
- return cart.amounts.total;
2665
- }
2666
-
2667
- // ✅ Use UI helpers that auto-update
2668
- client.ui.cartSubtotal('cart-total-display');
2669
- client.ui.cartItemsCount('cart-count-display');
2670
-
2671
- // Or cache and listen to updates
2672
- let cachedCart = await client.actions.cart.getDetails();
2673
- window.addEventListener('lce:actions.cart_updated', (event) => {
2674
- cachedCart = event.detail.data.current;
2675
- });
2676
- ```
2677
-
2678
- ### Use CDN for Production
2679
-
2680
- Always use CDN in production for optimal caching:
67
+ ## Core Concepts (Short)
2681
68
 
2682
- ```js
2683
- // CDN (recommended)
2684
- <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
69
+ - **Web Components + Shadow DOM** for framework-agnostic UI and style isolation
70
+ - **Declarative setup** via HTML data attributes
71
+ - **Programmatic setup** via `Elements()` client for dynamic injection
72
+ - **Events** for analytics and custom UI
73
+ - **Actions API** for cart/checkout control
2685
74
 
2686
- // ❌ Don't self-host unless necessary
2687
- <script src="/static/elements.js"></script>
2688
- ```
75
+ ## Components
2689
76
 
2690
- ### Minimize Theme Complexity
77
+ - **Product**: Images, variants, fulfillment, add-to-cart
78
+ - **Cart**: Drawer with items, totals, promo codes
79
+ - **Checkout**: Drawer or hosted page with full purchase flow
80
+ - **Address**: Delivery location capture
81
+ - **Product List**: Filterable, searchable grids
2691
82
 
2692
- Simpler themes = faster rendering:
83
+ ## Key Methods (High Level)
2693
84
 
2694
- ```js
2695
- // Don't override every style property
2696
- customTheme: {
2697
- global: {
2698
- colors: { /* 20 color overrides */ },
2699
- typography: { /* 15 typography overrides */ },
2700
- shadows: { /* 10 shadow overrides */ },
2701
- // ... 100 more overrides
2702
- }
2703
- }
85
+ - `injectProductElement`, `injectCartElement`, `injectCheckoutElement`, `injectAddressElement`
86
+ - `ui.cartButton`, `ui.floatingCartButton`, `ui.cartSubtotal`, `ui.cartItemsCount`
87
+ - `actions.product`, `actions.cart`, `actions.checkout`, `actions.address`
2704
88
 
2705
- // ✅ Override only what's necessary
2706
- customTheme: {
2707
- global: {
2708
- colors: {
2709
- primary: '#007bff',
2710
- secondary: '#6c757d'
2711
- }
2712
- }
2713
- }
89
+ ```javascript
90
+ // Example: add a product and open cart
91
+ await window.elements.actions.cart.addProduct([
92
+ { identifier: '00619947000020', fulfillmentType: 'shipping', quantity: 1 }
93
+ ], true);
2714
94
  ```
2715
95
 
2716
- ### Monitor Performance
96
+ ## Events (High Level)
2717
97
 
2718
- Track SDK performance in production:
2719
-
2720
- ```js
2721
- // Measure initialization time
2722
- const start = performance.now();
2723
- const client = await Elements('YOUR_API_KEY', { env: 'production' });
2724
- console.log(`SDK initialized in ${performance.now() - start}ms`);
98
+ Listen for SDK events to drive analytics or custom UI:
2725
99
 
2726
- // Track component load times
100
+ ```javascript
2727
101
  window.addEventListener('lce:actions.product_loaded', (event) => {
2728
- const { loadTime } = event.detail.metadata;
2729
- console.log(`Product loaded in ${loadTime}ms`);
2730
-
2731
- // Send to analytics
2732
- analytics.track('SDK Component Load', {
2733
- component: 'product',
2734
- duration: loadTime
2735
- });
102
+ console.log('Loaded:', event.detail.data.identifier);
2736
103
  });
2737
- ```
2738
-
2739
- ### Production Checklist
2740
-
2741
- Before going live:
2742
-
2743
- - ✅ Set `env: 'production'`
2744
- - ✅ Set `debugMode: 'none'` (or omit)
2745
- - ✅ Use CDN script URL
2746
- - ✅ Pin to specific version (optional but recommended)
2747
- - ✅ Configure proxy if using ad blockers
2748
- - ✅ Test error handling
2749
- - ✅ Verify event tracking
2750
- - ✅ Check cart persistence
2751
- - ✅ Test on target browsers
2752
- - ✅ Measure performance metrics
2753
104
 
2754
- **Production-ready init:**
2755
-
2756
- ```js
2757
- const client = await Elements('YOUR_PRODUCTION_API_KEY', {
2758
- env: 'production',
2759
- debugMode: 'none',
2760
- customTheme: { /* minimal overrides */ },
2761
- proxy: { baseUrl: 'https://yourdomain.com/api/proxy' }
105
+ window.addEventListener('lce:actions.checkout_submit_completed', (event) => {
106
+ console.log('Order:', event.detail.data.orderId);
2762
107
  });
2763
108
  ```
2764
109
 
2765
- **📖 For debugging and troubleshooting:** See [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for comprehensive problem-solving guide.
2766
-
2767
- ---
2768
-
2769
- ## 🔒 Proxy Configuration
2770
-
2771
- Route API requests through your server to avoid ad blockers:
110
+ ## Theming
2772
111
 
2773
- ```js
112
+ ```javascript
2774
113
  const client = await Elements('YOUR_API_KEY', {
2775
114
  env: 'production',
2776
- proxy: {
2777
- baseUrl: 'https://yourdomain.com/api/liquidcommerce',
2778
- headers: {
2779
- 'X-Custom-Header': 'value'
115
+ customTheme: {
116
+ global: {
117
+ theme: {
118
+ primaryColor: '#007bff',
119
+ buttonCornerRadius: '8px'
120
+ }
2780
121
  }
2781
122
  }
2782
123
  });
2783
124
  ```
2784
125
 
2785
- The SDK automatically handles routing and required headers. See [`docs/PROXY.md`](docs/PROXY.md) for complete proxy setup guide with Next.js examples.
2786
-
2787
- ## 📚 Documentation
126
+ ## Integrations
2788
127
 
2789
- **📖 Complete Documentation:**
128
+ Works with any framework. See:
2790
129
 
2791
- - **[Documentation Index](docs/DOCUMENTATION_INDEX.md)** - Complete guide to all documentation
2792
- - **[Configuration Reference](docs/CONFIGURATION.md)** - All configuration options with TypeScript types
2793
- - **[Theming Guide](docs/THEMING.md)** - Complete customization reference
2794
- - **[Actions Reference](docs/ACTIONS.md)** - Programmatic control with business use cases
2795
- - **[Events Reference](docs/EVENTS.md)** - Event system and tracking guide
2796
- - **[Troubleshooting Guide](docs/TROUBLESHOOTING.md)** - Common issues and solutions
2797
- - **[Browser Support](docs/BROWSER_SUPPORT.md)** - Detailed browser compatibility
2798
- - **[Proxy Setup](docs/PROXY.md)** - Ad blocker avoidance configuration
130
+ - [React](./docs/v1/integration/react.md)
131
+ - [Next.js](./docs/v1/integration/nextjs.md)
132
+ - [Vue](./docs/v1/integration/vue.md)
133
+ - [Angular](./docs/v1/integration/angular.md)
134
+ - [Laravel](./docs/v1/integration/laravel.md)
135
+ - [Vanilla JS](./docs/v1/integration/vanilla-js.md)
136
+ - [Proxy Setup](./docs/v1/integration/proxy-setup.md)
2799
137
 
2800
- ---
2801
-
2802
- ## 🏷️ Versioning
2803
-
2804
- This project uses Semantic Versioning. Two CDN environments are available:
2805
-
2806
- - **Production:** `https://assets-elements.liquidcommerce.us/all/elements.js` (stable)
2807
- - **Beta:** `https://assets-elements.liquidcommerce.us/all/beta/elements.js` (pre-release)
138
+ ## Documentation (v1)
2808
139
 
2809
- ## 💬 Support
140
+ - [Start Here](./docs/v1/README.md)
141
+ - [Getting Started](./docs/v1/getting-started/installation.md)
142
+ - [Guides](./docs/v1/guides/)
143
+ - [API Reference](./docs/v1/api/)
144
+ - [Examples](./docs/v1/examples/)
145
+ - [Reference](./docs/v1/reference/)
2810
146
 
2811
- If you need help with your API key, environment selection, or implementation, contact your LiquidCommerce representative.
2812
-
2813
- ---
2814
-
2815
- <div align="center">
147
+ ## Browser Support
2816
148
 
2817
- **Built with ❤️ by the LiquidCommerce Team**
149
+ Chrome 66+, Firefox 60+, Safari 12+, Edge 79+.
150
+ See [Browser Support](./docs/v1/reference/browser-support.md) for details.
2818
151
 
2819
- [Actions Reference](docs/ACTIONS.md) • [Events Guide](docs/EVENTS.md) • [Browser Support](docs/BROWSER_SUPPORT.md) • [Proxy Setup](docs/PROXY.md)
152
+ ## Support
2820
153
 
2821
- </div>
154
+ Contact your LiquidCommerce representative for assistance.