@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.
- package/README.md +83 -2750
- package/dist/index.checkout.esm.js +6898 -6837
- package/dist/index.esm.js +11463 -10993
- package/dist/types/auto-initialize/shared-utils.d.ts +5 -0
- package/dist/types/constants/core.constant.d.ts +0 -4
- package/dist/types/core/base-component.service.d.ts +2 -1
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +1 -0
- package/dist/types/enums/core.enum.d.ts +11 -0
- package/dist/types/interfaces/configs/product-list.interface.d.ts +2 -2
- package/dist/types/interfaces/core.interface.d.ts +5 -4
- package/dist/types/modules/address/address-input.component.d.ts +11 -0
- package/dist/types/modules/checkout/components/checkout-stripe-form.component.d.ts +2 -1
- package/dist/types/modules/product-list/components/card-components/index.d.ts +3 -0
- package/dist/types/modules/product-list/components/card-components/product-badge.d.ts +8 -0
- package/dist/types/modules/product-list/components/card-components/product-fulfillments.d.ts +2 -0
- package/dist/types/modules/product-list/components/card-components/product-price-and-personalization.d.ts +13 -0
- package/dist/types/modules/product-list/components/card-components/product-title.d.ts +6 -0
- package/dist/types/modules/product-list/components/index.d.ts +1 -0
- package/dist/types/modules/product-list/components/product-list-engraving.component.d.ts +5 -1
- package/dist/types/modules/product-list/components/product-list-product-pre-cart.component.d.ts +28 -0
- package/dist/types/modules/product-list/components/product-list-retailers.component.d.ts +10 -2
- package/dist/types/modules/product-list/product-list-card.component.d.ts +0 -5
- package/dist/types/modules/product-list/product-list.commands.d.ts +11 -2
- package/dist/types/modules/product-list/product-list.interface.d.ts +1 -0
- package/dist/types/modules/ui-components/engraving/engraving-form.component.d.ts +11 -2
- package/dist/types/modules/ui-components/lce-element/lce-element.component.d.ts +2 -1
- package/dist/types/utils/dom-compat.d.ts +2 -0
- package/docs/gitbook/actions.md +964 -0
- package/docs/gitbook/address.md +48 -0
- package/docs/gitbook/cart.md +65 -0
- package/docs/gitbook/checkout.md +131 -0
- package/docs/gitbook/events.md +1765 -0
- package/docs/gitbook/overview.md +166 -0
- package/docs/gitbook/product.md +64 -0
- package/docs/gitbook/quick-start-guide.md +393 -0
- package/docs/v1/README.md +210 -0
- package/docs/v1/api/actions/address-actions.md +281 -0
- package/docs/v1/api/actions/cart-actions.md +337 -0
- package/docs/v1/api/actions/checkout-actions.md +387 -0
- package/docs/v1/api/actions/product-actions.md +115 -0
- package/docs/v1/api/client.md +482 -0
- package/docs/v1/api/configuration.md +1 -0
- package/docs/v1/api/injection-methods.md +247 -0
- package/docs/v1/api/typescript-types.md +1 -0
- package/docs/v1/api/ui-helpers.md +200 -0
- package/docs/v1/examples/advanced-patterns.md +96 -0
- package/docs/v1/examples/checkout-flow.md +91 -0
- package/docs/v1/examples/custom-theming.md +63 -0
- package/docs/v1/examples/multi-product-page.md +90 -0
- package/docs/v1/examples/simple-product-page.md +89 -0
- package/docs/v1/getting-started/concepts.md +507 -0
- package/docs/v1/getting-started/installation.md +328 -0
- package/docs/v1/getting-started/quick-start.md +405 -0
- package/docs/v1/guides/address-component.md +431 -0
- package/docs/v1/guides/best-practices.md +324 -0
- package/docs/v1/guides/cart-component.md +737 -0
- package/docs/v1/guides/checkout-component.md +672 -0
- package/docs/v1/guides/events.md +926 -0
- package/docs/v1/guides/product-component.md +686 -0
- package/docs/v1/guides/product-list-component.md +598 -0
- package/docs/v1/guides/theming.md +216 -0
- package/docs/v1/integration/angular.md +39 -0
- package/docs/v1/integration/laravel.md +41 -0
- package/docs/v1/integration/nextjs.md +60 -0
- package/docs/v1/integration/proxy-setup.md +89 -0
- package/docs/v1/integration/react.md +64 -0
- package/docs/v1/integration/vanilla-js.md +84 -0
- package/docs/v1/integration/vue.md +34 -0
- package/docs/v1/reference/browser-support.md +44 -0
- package/docs/v1/reference/error-handling.md +70 -0
- package/docs/v1/reference/performance.md +54 -0
- package/docs/v1/reference/troubleshooting.md +64 -0
- package/package.json +1 -1
- package/docs/ACTIONS.md +0 -1301
- package/docs/BROWSER_SUPPORT.md +0 -279
- package/docs/CONFIGURATION.md +0 -997
- package/docs/DOCUMENTATION_INDEX.md +0 -319
- package/docs/EVENTS.md +0 -798
- package/docs/PROXY.md +0 -228
- package/docs/THEMING.md +0 -681
- package/docs/TROUBLESHOOTING.md +0 -793
package/README.md
CHANGED
|
@@ -9,2813 +9,146 @@ Elements SDK
|
|
|
9
9
|
|
|
10
10
|
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
|
11
11
|
[](https://www.typescriptlang.org/)
|
|
12
|
-
[
|
|
15
|
-
|
|
16
|
-
[](LICENSE)
|
|
17
|
-
[](./package.json)
|
|
18
|
-
[](./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
|
+
[](./package.json)
|
|
13
|
+
[](./docs/v1/reference/browser-support.md)
|
|
2191
14
|
|
|
2192
|
-
|
|
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
|
-
|
|
2203
|
-
// - Consistent state
|
|
2204
|
-
// - Efficient memory usage
|
|
2205
|
-
// - No duplicate API calls
|
|
2206
|
-
```
|
|
17
|
+
</div>
|
|
2207
18
|
|
|
2208
19
|
---
|
|
2209
20
|
|
|
2210
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
2317
|
-
}
|
|
2318
|
-
```
|
|
2319
|
-
|
|
2320
|
-
### WordPress Integration
|
|
25
|
+
## What You Can Build
|
|
2321
26
|
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
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
|
-
|
|
2332
|
-
<div data-lce-product="<?php echo get_post_meta(get_the_ID(), 'product_upc', true); ?>"></div>
|
|
2333
|
-
```
|
|
33
|
+
## Installation
|
|
2334
34
|
|
|
2335
|
-
###
|
|
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="
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
2545
|
-
|
|
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
|
-
|
|
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
|
-
|
|
61
|
+
const client = await Elements('YOUR_API_KEY', { env: 'production' });
|
|
2564
62
|
await client.injectProductElement([
|
|
2565
|
-
{ containerId: '
|
|
2566
|
-
{ containerId: 'p2', identifier: 'id2' },
|
|
2567
|
-
{ containerId: 'p3', identifier: 'id3' }
|
|
63
|
+
{ containerId: 'product', identifier: '00619947000020' }
|
|
2568
64
|
]);
|
|
2569
65
|
```
|
|
2570
66
|
|
|
2571
|
-
|
|
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
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
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
|
-
|
|
2687
|
-
<script src="/static/elements.js"></script>
|
|
2688
|
-
```
|
|
75
|
+
## Components
|
|
2689
76
|
|
|
2690
|
-
|
|
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
|
-
|
|
83
|
+
## Key Methods (High Level)
|
|
2693
84
|
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
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
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
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
|
-
|
|
96
|
+
## Events (High Level)
|
|
2717
97
|
|
|
2718
|
-
|
|
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
|
-
|
|
100
|
+
```javascript
|
|
2727
101
|
window.addEventListener('lce:actions.product_loaded', (event) => {
|
|
2728
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2766
|
-
|
|
2767
|
-
---
|
|
2768
|
-
|
|
2769
|
-
## 🔒 Proxy Configuration
|
|
2770
|
-
|
|
2771
|
-
Route API requests through your server to avoid ad blockers:
|
|
110
|
+
## Theming
|
|
2772
111
|
|
|
2773
|
-
```
|
|
112
|
+
```javascript
|
|
2774
113
|
const client = await Elements('YOUR_API_KEY', {
|
|
2775
114
|
env: 'production',
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
115
|
+
customTheme: {
|
|
116
|
+
global: {
|
|
117
|
+
theme: {
|
|
118
|
+
primaryColor: '#007bff',
|
|
119
|
+
buttonCornerRadius: '8px'
|
|
120
|
+
}
|
|
2780
121
|
}
|
|
2781
122
|
}
|
|
2782
123
|
});
|
|
2783
124
|
```
|
|
2784
125
|
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
## 📚 Documentation
|
|
126
|
+
## Integrations
|
|
2788
127
|
|
|
2789
|
-
|
|
128
|
+
Works with any framework. See:
|
|
2790
129
|
|
|
2791
|
-
-
|
|
2792
|
-
-
|
|
2793
|
-
-
|
|
2794
|
-
-
|
|
2795
|
-
-
|
|
2796
|
-
-
|
|
2797
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
2812
|
-
|
|
2813
|
-
---
|
|
2814
|
-
|
|
2815
|
-
<div align="center">
|
|
147
|
+
## Browser Support
|
|
2816
148
|
|
|
2817
|
-
|
|
149
|
+
Chrome 66+, Firefox 60+, Safari 12+, Edge 79+.
|
|
150
|
+
See [Browser Support](./docs/v1/reference/browser-support.md) for details.
|
|
2818
151
|
|
|
2819
|
-
|
|
152
|
+
## Support
|
|
2820
153
|
|
|
2821
|
-
|
|
154
|
+
Contact your LiquidCommerce representative for assistance.
|