> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Shopify/horizon/llms.txt
> Use this file to discover all available pages before exploring further.

# Cart & Checkout Features

> Cart page with dynamic updates, summary sidebar, and flexible layout

The Horizon cart provides a responsive, feature-rich shopping cart experience with real-time updates, summary sidebar, and customizable blocks.

## Key Features

* **Dynamic Updates**: Real-time cart updates without page reload
* **Responsive Layout**: Two-column desktop, single-column mobile
* **Cart Summary Sidebar**: Sticky summary with totals and checkout button
* **Empty State**: Custom empty cart display
* **View Transitions**: Smooth animations for cart changes
* **Flexible Blocks**: Add custom content blocks to cart page

## Cart Structure

The cart uses a component-based architecture:

```liquid theme={null}
<cart-items-component
  class="cart-items-component"
  data-section-id="{{ section.id }}"
>
  <!-- Empty cart template -->
  <template id="empty-cart-template">
    <!-- Rendered when cart is empty -->
  </template>
  
  <!-- Main cart display -->
  <div class="cart-page">
    <div class="cart-page__title">...</div>
    <div class="cart-page__items">...</div>
    <div class="cart-page__summary">...</div>
  </div>
</cart-items-component>
```

## Cart Components

### Cart Title

```liquid theme={null}
<div class="cart-page__title">
  {% content_for 'block',
    id: 'cart-page-title',
    type: '_cart-title'
  %}
</div>
```

Displays the cart heading (e.g., "Your Cart").

### Cart Items

```liquid theme={null}
<div class="cart-page__items">
  {% content_for 'block',
    id: 'cart-page-items',
    type: '_cart-products'
  %}
</div>
```

**Features:**

* Product thumbnails
* Variant information
* Quantity selectors
* Remove buttons
* Line item properties
* Real-time price updates

### Cart Summary

```liquid theme={null}
{% unless cart.empty? %}
  <div class="cart-page__summary">
    {% content_for 'block',
      id: 'cart-page-summary',
      type: '_cart-summary'
    %}
  </div>
{% endunless %}
```

**Includes:**

* Subtotal
* Shipping estimate
* Tax information
* Discount codes
* Total price
* Checkout button
* Payment icons (optional)

### Additional Blocks

```liquid theme={null}
<div class="cart-page__more-blocks">
  {% content_for 'blocks' %}
</div>
```

Supports custom blocks:

* Text
* Images
* Icons
* Buttons
* Videos
* Groups
* Spacers

## Layout System

### Desktop Layout

Two-column layout with sidebar on medium+ screens:

```css theme={null}
@media screen and (min-width: 750px) {
  .cart-page {
    display: grid;
    grid-template-columns: 1fr min(50vw, var(--sidebar-width));
    grid-template-rows: min-content min-content 1fr;
    gap: 0 var(--padding-5xl);
  }
  
  .cart-page__summary {
    grid-column: 2;
    grid-row: 1 / -1;
    align-self: stretch;
    grid-template-rows: subgrid;
  }
}
```

**Grid Areas:**

* Column 1: Title + Items
* Column 2: Summary (spans all rows)

### Mobile Layout

Single-column stacked layout:

```css theme={null}
.cart-page {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}

.cart-page__summary {
  padding-top: var(--padding-xl);
}
```

### Extended Summary

For page-width layouts, summary can extend to viewport edge:

```css theme={null}
@media screen and (min-width: 750px) {
  .section--page-width .cart-page:has(.cart-summary--extend) {
    grid-column: 2 / 4;
    grid-template-columns: 1fr minmax(
      var(--sidebar-width),
      calc((100vw - var(--page-width)) / 2 + var(--sidebar-width))
    );
  }
}
```

<Note>
  This creates a bleed effect where the summary extends to the edge of the viewport while content stays within page width.
</Note>

## Empty Cart State

Custom template for when cart is empty:

```liquid theme={null}
<template id="empty-cart-template">
  <div class="cart-page spacing-style cart-page--empty">
    <div class="cart-page__title">
      {% content_for 'block',
        id: 'cart-page-title',
        type: '_cart-title',
        force_empty: true
      %}
    </div>
    
    <div class="cart-page__items">
      {% content_for 'block',
        id: 'cart-page-items',
        type: '_cart-products',
        force_empty: true
      %}
    </div>
    
    {{ cart_page_more_blocks_content }}
  </div>
</template>
```

**Empty State Styling:**

```css theme={null}
.cart-page--empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.cart-page--empty .cart-page__title,
.cart-page--empty .cart-page__more-blocks {
  margin-top: var(--margin-6xl);
}

.cart-page--empty .cart-title {
  text-align: center;
}
```

## Dynamic Cart Updates

The cart automatically updates without page reload:

### Quantity Changes

```javascript theme={null}
// Quantity selectors trigger cart updates
<input type="number" 
       name="updates[]" 
       value="{{ item.quantity }}"
       min="0"
       data-line="{{ forloop.index }}">
```

### Remove Items

```liquid theme={null}
<button type="button"
        data-line="{{ forloop.index }}"
        aria-label="{{ 'cart.remove' | t }}">
  Remove
</button>
```

### Cart API

Uses Shopify Cart API for updates:

```javascript theme={null}
// Update quantity
fetch('/cart/update.js', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    updates: { [variantId]: quantity }
  })
});

// Remove item
fetch('/cart/change.js', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    line: lineNumber,
    quantity: 0
  })
});
```

## View Transitions

Smooth animations when cart becomes empty:

```css theme={null}
html:active-view-transition-type(empty-cart-page) {
  .cart-items-component {
    view-transition-name: cart-page-content;
  }
}

::view-transition-old(cart-page-content) {
  animation: cart-page-content-old var(--animation-speed-fast) 
             var(--animation-easing) forwards;
}

@keyframes cart-page-content-old {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
    filter: blur(4px);
  }
}
```

## Supported Block Types

<Tabs>
  <Tab title="Theme Blocks">
    ```json theme={null}
    {
      "type": "@theme"
    }
    ```

    Access to all theme blocks like product cards, collection lists, etc.
  </Tab>

  <Tab title="App Blocks">
    ```json theme={null}
    {
      "type": "@app"
    }
    ```

    Third-party app integrations (upsells, recommendations, etc.)
  </Tab>

  <Tab title="Content Blocks">
    * `text` - Rich text content
    * `icon` - Icon with optional text
    * `image` - Custom images
    * `button` - Call-to-action buttons
    * `video` - Embedded videos
  </Tab>

  <Tab title="Layout Blocks">
    * `group` - Group multiple blocks
    * `spacer` - Add vertical spacing
  </Tab>
</Tabs>

## Settings

### Section Width

```yaml theme={null}
section_width:
  options:
    - page-width (default)
    - full-width
  default: page-width
```

### Color Scheme

```yaml theme={null}
color_scheme:
  type: color_scheme
  default: scheme-1
```

### Padding

<CodeGroup>
  ```yaml Top Padding theme={null}
  padding-block-start:
    min: 0
    max: 100
    step: 1
    unit: px
    default: 0
  ```

  ```yaml Bottom Padding theme={null}
  padding-block-end:
    min: 0
    max: 100
    step: 1
    unit: px
    default: 0
  ```
</CodeGroup>

## Spacing Between Sections

```css theme={null}
.cart-page__title + .cart-page__items {
  margin-block-start: var(--margin-lg);
}

.cart-page__summary {
  padding-top: var(--padding-xl);
}

@media screen and (min-width: 750px) {
  .cart-page__summary {
    padding-top: 0;
  }
}
```

## Responsive Breakpoints

<Tabs>
  <Tab title="Mobile">
    **\< 750px**

    * Single column layout
    * Summary below items
    * Full-width elements
    * Touch-optimized quantity selectors
  </Tab>

  <Tab title="Tablet">
    **750px - 1399px**

    * Two-column layout
    * Summary sidebar (50vw max)
    * Side-by-side items and summary
  </Tab>

  <Tab title="Desktop">
    **≥ 1400px**

    * Two-column layout
    * Summary sidebar (fixed width)
    * Maximum readability
  </Tab>
</Tabs>

## Performance Optimizations

### Debounced Updates

Quantity changes are debounced to prevent excessive API calls:

```javascript theme={null}
let updateTimeout;
function updateQuantity(line, quantity) {
  clearTimeout(updateTimeout);
  updateTimeout = setTimeout(() => {
    // Update cart via API
  }, 300);
}
```

### Section Rendering

Cart uses section rendering for partial updates:

```javascript theme={null}
fetch(`${window.location.pathname}?section_id=${sectionId}`)
  .then(response => response.text())
  .then(html => {
    // Update only cart section, not entire page
  });
```

## Accessibility

<AccordionGroup>
  <Accordion title="ARIA Labels">
    ```liquid theme={null}
    <div role="region" aria-label="{{ 'cart.title' | t }}">
      <table role="table" aria-label="{{ 'cart.items' | t }}">
        <tr role="row">
          <td role="cell">...</td>
        </tr>
      </table>
    </div>
    ```
  </Accordion>

  <Accordion title="Live Regions">
    ```liquid theme={null}
    <div role="status" aria-live="polite" aria-atomic="true">
      {{ 'cart.item_updated' | t }}
    </div>
    ```

    Announces cart updates to screen readers.
  </Accordion>

  <Accordion title="Keyboard Navigation">
    * Tab through all interactive elements
    * Enter/Space to activate buttons
    * Arrow keys for quantity steppers
    * Focus visible on all controls
  </Accordion>

  <Accordion title="Form Labels">
    ```liquid theme={null}
    <label for="quantity-{{ item.key }}">
      {{ 'cart.quantity' | t }}
    </label>
    <input id="quantity-{{ item.key }}" type="number">
    ```
  </Accordion>
</AccordionGroup>

## Schema Configuration

```json theme={null}
{
  "name": "Cart",
  "disabled_on": {
    "groups": ["header", "footer"]
  },
  "blocks": [
    { "type": "@theme" },
    { "type": "@app" },
    { "type": "text" },
    { "type": "icon" },
    { "type": "image" },
    { "type": "button" },
    { "type": "video" },
    { "type": "group" },
    { "type": "spacer" }
  ],
  "settings": [
    {
      "type": "select",
      "id": "section_width",
      "label": "Width",
      "options": [
        { "value": "page-width", "label": "Page" },
        { "value": "full-width", "label": "Full" }
      ],
      "default": "page-width"
    },
    {
      "type": "color_scheme",
      "id": "color_scheme",
      "label": "Color scheme",
      "default": "scheme-1"
    },
    {
      "type": "range",
      "id": "padding-block-start",
      "label": "Top padding",
      "min": 0,
      "max": 100,
      "step": 1,
      "unit": "px",
      "default": 0
    },
    {
      "type": "range",
      "id": "padding-block-end",
      "label": "Bottom padding",
      "min": 0,
      "max": 100,
      "step": 1,
      "unit": "px",
      "default": 0
    }
  ]
}
```

## Cart Summary Blocks

The `_cart-summary` block renders:

1. **Subtotal Display**
   ```liquid theme={null}
   <div class="cart-summary__subtotal">
     <span>{{ 'cart.subtotal' | t }}</span>
     <span>{{ cart.total_price | money }}</span>
   </div>
   ```

2. **Shipping Calculator** (optional)
   ```liquid theme={null}
   {% if settings.enable_shipping_calculator %}
     <div class="cart-summary__shipping">
       {% render 'shipping-calculator' %}
     </div>
   {% endif %}
   ```

3. **Discount Code Input**
   ```liquid theme={null}
   <form class="cart-summary__discount">
     <input type="text" name="discount" placeholder="{{ 'cart.discount_code' | t }}">
     <button type="submit">{{ 'cart.apply' | t }}</button>
   </form>
   ```

4. **Total Price**
   ```liquid theme={null}
   <div class="cart-summary__total">
     <span>{{ 'cart.total' | t }}</span>
     <strong>{{ cart.total_price | money }}</strong>
   </div>
   ```

5. **Checkout Button**
   ```liquid theme={null}
   <button type="submit" name="checkout" class="button button--primary">
     {{ 'cart.checkout' | t }}
   </button>
   ```

## Notes API Integration

Cart supports order notes:

```liquid theme={null}
<div class="cart-summary__note">
  <label for="cart-note">{{ 'cart.note' | t }}</label>
  <textarea id="cart-note" name="note">{{ cart.note }}</textarea>
</div>
```

## Attributes API

Support for cart attributes:

```liquid theme={null}
<input type="text" 
       name="attributes[Gift message]" 
       value="{{ cart.attributes['Gift message'] }}">
```
