# Core Concepts

Understanding these fundamental concepts will help you work effectively with the LiquidCommerce Elements SDK.

## Web Components Architecture

The Elements SDK is built using **Web Components**, a set of web platform APIs that allow you to create custom, reusable HTML elements.

### What Are Web Components?

Web Components are native browser features that provide:

1. **Custom Elements** - Define your own HTML tags
2. **Shadow DOM** - Encapsulated styling and markup
3. **HTML Templates** - Reusable DOM fragments

### Why Web Components?

**Framework Agnostic**  
Works with any JavaScript framework or plain HTML:
- React, Vue, Angular, Svelte
- Vanilla JavaScript
- Static HTML pages
- Server-rendered pages

**Style Encapsulation**  
Shadow DOM prevents CSS conflicts:
- SDK styles don't leak into your page
- Your page styles don't affect the SDK
- Components look consistent everywhere

**Future-Proof**  
Built on web standards:
- No framework lock-in
- Works in modern browsers natively
- Follows platform evolution

### How It Works

When you inject a product:

```javascript
await client.injectProductElement([
  { containerId: 'product', identifier: '00619947000020' }
]);
```

The SDK:
1. Creates a custom element (e.g., `<product-lc>`)
2. Attaches it to your container
3. Renders content in Shadow DOM
4. Registers event listeners

## Client Initialization

The SDK client is the main interface for all operations.

### Initialization Modes

#### Auto-Initialization (CDN)

When using the CDN, the SDK auto-initializes on page load:

```html
<script
  defer
  data-liquid-commerce-elements
  data-token="YOUR_API_KEY"
  data-env="production"
  type="text/javascript"
  src="https://elements.reservebar-worker.workers.dev/all/elements.js"
></script>
```

The client becomes available globally under `window.LiquidCommerce.elements`.

#### Programmatic Initialization (NPM)

With NPM, you explicitly create the client:

```javascript
import { Elements } from '@liquidcommerce/elements-sdk';

const client = await Elements('YOUR_API_KEY', {
  env: 'production'
});
```

### Phased Initialization

The SDK uses a two-phase initialization strategy for optimal performance:

**Phase 1: Essential Services (Immediate)**
- Authentication
- Configuration loading
- Store initialization
- Theme setup
- Core component registration
- Telemetry / logger wiring
- Debug panel (if enabled)

**Phase 2: Deferred Services (next macrotask, via `setTimeout(…, 0)`)**
- Analytics (Google Tag Manager)
- Cart pre-loading
- Heavy component registration

This ensures fast initial page loads while still providing full functionality.

### Client Ready Event

Listen for the client ready event to know when the SDK is initialized:

```javascript
window.addEventListener('lce:actions.client_ready', (event) => {
  console.log('SDK version:', event.detail.data.version);
  console.log('Ready at:', event.detail.data.timestamp);
  
  // Safe to use client
  window.LiquidCommerce.elements.actions.cart.openCart();
});
```

## Declarative vs Programmatic

The SDK offers two approaches for component injection.

### Declarative (HTML Attributes)

Configure components using HTML data attributes:

```html
<script
  defer
  data-liquid-commerce-elements
  data-token="YOUR_API_KEY"
  data-container-1="product"
  data-product-1="00619947000020"
  type="text/javascript"
  src="https://elements.reservebar-worker.workers.dev/all/elements.js"
></script>

<div id="product"></div>
```

**Advantages:**
- No JavaScript required
- Simple for static pages
- Automatic initialization

**Best for:**
- Static HTML sites
- CMS platforms (WordPress, Shopify)
- Quick prototypes

### Programmatic (JavaScript API)

Use JavaScript methods to inject components:

```javascript
const client = await Elements('YOUR_API_KEY', { env: 'production' });

await client.injectProductElement([
  { containerId: 'product', identifier: '00619947000020' }
]);
```

**Advantages:**
- Dynamic product selection
- Conditional rendering
- Framework integration
- Full control over timing

**Best for:**
- Single-page applications
- Dynamic content
- React/Vue/Angular apps
- Complex interactions

### Mixing Both Approaches

You can use declarative initialization and programmatic control:

```html
<!-- Auto-initialize SDK -->
<script
  defer
  data-liquid-commerce-elements
  data-token="YOUR_API_KEY"
  data-env="production"
  type="text/javascript"
  src="https://elements.reservebar-worker.workers.dev/all/elements.js"
></script>

<script>
// Later, add products programmatically
window.addEventListener('lce:actions.client_ready', async () => {
  await window.LiquidCommerce.elements.injectProductElement([
    { containerId: 'dynamic-product', identifier: selectedProductId }
  ]);
});
</script>
```

## State Management

The SDK maintains its own internal state for cart, checkout, and user data.

### Store Service

The SDK uses a centralized store service that:
- Maintains reactive state (in-memory, within a single tab)
- Persists data to localStorage
- Falls back to API storage

### State Persistence

**Cart State:**
- Saved to localStorage
- Persists across sessions
- Survives page refreshes
- Other tabs pick up the persisted cart on their next load (no live cross-tab sync)

**Address State:**
- Saved when set by user
- Used for availability checking
- Cleared when user explicitly clears it

**Checkout State:**
- Created from cart
- Exists during checkout flow
- Cleared after order completion

### Cross-Tab Persistence

State is persisted to `localStorage` keyed by device ID. The SDK does **not** register a `storage` listener, `BroadcastChannel`, or other inter-tab subscription, so there is **no live cross-tab synchronization** — a change made in one tab is only reflected in another already-open tab after that tab reloads (which re-runs the persisted-state load and re-fetches by the persisted cart ID).

## Component Lifecycle

Understanding how components work helps with debugging and customization.

### Injection Lifecycle

1. **Validation** - Verify container exists
2. **Creation** - Create Web Component
3. **Attachment** - Add to DOM
4. **Data Loading** - Fetch product/cart data
5. **Rendering** - Display content
6. **Event Setup** - Register listeners

### Component Rerendering

Components automatically rerender when data changes:

```javascript
// This triggers a rerender
await window.LiquidCommerce.elements.actions.cart.addProduct([...]);
// Cart component updates automatically
```

Manual rerendering:

```javascript
const components = window.LiquidCommerce.elements.getInjectedComponents();
// The Map is keyed by the container ID passed to inject* (with any leading '#' stripped),
// not a '<type>-<index>' string. For a component injected into id="product":
const productComponent = components.get('product');

// Force rerender
productComponent?.rerender();
```

### Component Removal

Components are removed when:
- Their container is removed from DOM
- Page navigation occurs
- You explicitly remove them

To clean up manually:

```javascript
const container = document.getElementById('product');
container.innerHTML = ''; // Removes the component
```

## Event System

The SDK uses a publish-subscribe pattern for events.

### Event Namespaces

All SDK events are namespaced to prevent conflicts:

```javascript
// Action events (user interactions)
lce:actions.cart_opened
lce:actions.product_add_to_cart

// Form events (checkout forms)
lce:forms.customer
lce:forms.billing
```

### Event Flow

1. User interacts with component
2. Component publishes event
3. SDK updates internal state
4. Event bubbles to window
5. Your code can listen and react

### Subscribing to Events

```javascript
window.addEventListener('lce:actions.cart_item_added', (event) => {
  console.log('Item added:', event.detail.data);
  // event.detail is { data, metadata }; payload fields live under .data:
  // { cartId, itemId, fulfillmentId, partNumber, quantity, engravingLines? }
});
```

See [Events Guide](../guides/events.md) for all available events.

## Error Handling

The SDK is designed to fail gracefully and not crash your site.

### Error Isolation

SDK errors are logged and also emitted as a `*_FAILED` event, then re-thrown so your code can catch them:

```javascript
// The SDK emits CART_PRODUCT_ADD_FAILED and re-throws, so this catch runs
try {
  await window.LiquidCommerce.elements.actions.cart.addProduct([/* invalid data */]);
} catch (error) {
  console.log('This error is re-thrown by the SDK and caught here');
}

// Your page keeps working
console.log('Page still functional');
```

### Error Types

The SDK uses a custom `SDKError` class for all errors:

```javascript
class SDKError extends Error {
  constructor(message, reThrow = false) {
    super(message);
    this.name = 'SDKError';
    this.isSdk = true;
    this.reThrow = reThrow; // Whether to re-throw to the user
  }
}
```

### Debug Mode

Enable debug mode for detailed logging:

```javascript
const client = await Elements('YOUR_API_KEY', {
  env: 'development',
  debugMode: 'console'  // or 'panel'
});
```

**Debug Modes:**
- `'none'` - No debug output (production default)
- `'console'` - Log to browser console
- `'panel'` - Show debug panel on page

## Security & API Keys

### API Key Protection

Your API key is used for authentication but has limited privileges:

- ✅ Read product catalog
- ✅ Create carts and orders
- ✅ Process payments
- ❌ Access other merchants' data
- ❌ Modify product catalog
- ❌ Access admin functions

### Environment Separation

Use different API keys per environment:

```javascript
// Development
const client = await Elements('dev_key_abc123', {
  env: 'development'
});

// Production
const client = await Elements('prod_key_xyz789', {
  env: 'production'
});
```

### Proxy Configuration

To hide your API key and avoid ad blockers, use a proxy:

```javascript
const client = await Elements('YOUR_API_KEY', {
  env: 'production',
  proxy: {
    baseUrl: 'https://yourdomain.com/api/elements-proxy'
  }
});
```

See [Proxy Setup Guide](../integration/proxy-setup.md) for implementation details.

## Browser Support

The SDK requires modern browser features:

**Minimum Versions:**
- Chrome 66+ (March 2018)
- Firefox 60+ (May 2018)
- Safari 12+ (September 2018)
- Edge 79+ (January 2020)

**Required Features:**
- Custom Elements (Web Components)
- Shadow DOM
- ES2018 JavaScript
- Fetch API
- LocalStorage

For older browsers, include polyfills:

```html
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-bundle.js"></script>
<script data-liquid-commerce-elements ...></script>
```

See [Browser Support](../reference/browser-support.md) for details.

## Performance Considerations

The SDK is optimized for performance, but you can help:

### Lazy Loading

Load the SDK script with `defer`:

```html
<script defer data-liquid-commerce-elements ...></script>
```

### Tree Shaking

Use the checkout-only build when you don't need products:

```javascript
import { ElementsCheckout } from '@liquidcommerce/elements-sdk/checkout';
```

This reduces bundle size by ~60%.

### Component Injection Timing

Inject components when needed, not all at once:

```javascript
// Good: Inject visible products first
await client.injectProductElement([
  { containerId: 'hero-product', identifier: '001' }
]);

// Then inject others after a delay
setTimeout(async () => {
  await client.injectProductElement([
    { containerId: 'related-1', identifier: '002' },
    { containerId: 'related-2', identifier: '003' }
  ]);
}, 1000);
```

### Image Optimization

The SDK automatically:
- Lazy loads images
- Uses responsive images
- Implements carousel virtualization

## Next Steps

Now that you understand the core concepts:

- **[Product Component](../guides/product-component.md)** - Learn about product displays
- **[Cart Component](../guides/cart-component.md)** - Understand cart functionality
- **[Checkout Component](../guides/checkout-component.md)** - Master the checkout flow
- **[Theming](../guides/theming.md)** - Customize the look and feel
- **[Events](../guides/events.md)** - React to user actions
- **[API Reference](../api/client.md)** - Explore all available methods
