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

# Bloque Cart items

> El bloque Cart items: la lista de artículos de línea, la fila Product y el contenedor de los sub-bloques anidados.

> El bloque **Cart items** es la lista de artículos de línea del carrito, que renderiza cada producto que el comprador ha agregado con su imagen, título, variante, precio, control de cantidad y control de eliminación. Es un bloque obligatorio y es el contenedor que aloja los sub-bloques del carrito (la fila **Product**, [**Subscription upgrade**](/es/aftersell/cart/subscription-upgrade-block) y [**Custom code**](/es/aftersell/cart/custom-code-blocks)), proporcionando la estructura a la que se adjuntan los sub-bloques por línea.

<Frame>
  <img src="https://mintcdn.com/aftersell/1Y3gBpUfxv16VGSW/images/aftersell/cart-items-block-line-product-title-variant.png?fit=max&auto=format&n=1Y3gBpUfxv16VGSW&q=85&s=3c9f088b55cfd8450dcb8670dfe0728a" alt="Bloque Cart items mostrando artículos de línea con imagen del producto, título, variante, precio, control de cantidad y control de eliminación" width="1420" height="486" data-path="images/aftersell/cart-items-block-line-product-title-variant.png" />
</Frame>

<div id="the-product-row">
  ## La fila Product
</div>

Dentro de Cart items se encuentra el sub-bloque **Product**: la fila real del artículo de línea. Está bloqueada y se agrega automáticamente, por lo que cada bloque Cart items siempre tiene exactamente una fila Product que no puedes eliminar; reposicionas los otros sub-bloques alrededor de ella. Sus configuraciones controlan cómo se muestran los precios de cada línea:

| Configuración                              | Qué controla                                                                                                                                                                                                                                                                                                                                                                                              | Predeterminado                                  |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| **Strike-through price**                   | Qué precio se muestra tachado: **Compare-at or pre-discount, whichever is higher**, **Compare-at price**, **Pre-discount price** o **No strike-through**.                                                                                                                                                                                                                                                 | Compare-at or pre-discount, whichever is higher |
| **Strike-through price for subscriptions** | La misma elección para las líneas de suscripción, con dos diferencias: hay una opción adicional **Subscription compare-at price**, y **Compare-at price** pasa a llamarse **Product compare-at, then subscription compare-at**.                                                                                                                                                                           | Compare-at or pre-discount, whichever is higher |
| **Savings label**                          | Si los ahorros se muestran como **Amount**, **Percentage** o quedan en **Hidden**.                                                                                                                                                                                                                                                                                                                        | Amount                                          |
| **Bundle price**                           | Cómo se calcula el precio mostrado para las líneas de bundle. **Automatic** muestra el total de todos los artículos del bundle (o el precio del artículo principal cuando los otros artículos son gratis). **Main item price only** muestra solo el precio del artículo principal (ancla). Esto es solo una etiqueta de visualización: el total del carrito de Shopify siempre es la fuente autoritativa. | Automatic                                       |
| **Savings text**                           | La etiqueta de ahorros. Admite el token `{{value}}`.                                                                                                                                                                                                                                                                                                                                                      | `Save {{value}}`                                |

La fila en sí renderiza la imagen del producto (con enlace a la página del producto cuando está disponible), el título, la variante, el precio y cualquier precio compare-at tachado, un control de cantidad y un botón de eliminar. Las líneas de bundle muestran una lista desplegable de sus componentes.

<div id="text-styling">
  ### Estilo de texto
</div>

La fila Product incluye una sección **Text** en su configuración de Design. Úsala para controlar la tipografía de cada elemento de texto en cada artículo de línea. Selecciona un elemento de texto en el selector para ajustar su configuración:

| Configuración      | Qué controla                                                                                                                                                    |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Text color**     | Color del elemento de texto seleccionado.                                                                                                                       |
| **Font**           | **Theme font** (hereda la fuente de tu tema) o **Custom font** (escribe el nombre de una fuente que tu tema ya cargue). Disponible solo para **Product title**. |
| **Size**           | Tamaño de fuente en píxeles.                                                                                                                                    |
| **Weight**         | Grosor de la fuente: Light, Regular, Medium, Semibold o Bold.                                                                                                   |
| **Line height**    | Altura de línea como multiplicador del tamaño de fuente (por ejemplo, `1.4`).                                                                                   |
| **Letter spacing** | Espaciado entre letras en píxeles. Los valores negativos aprietan el texto.                                                                                     |

Los elementos de texto que puedes estilizar están agrupados por categoría:

**Product**

* **Product title** — el nombre del producto en cada línea. También admite una familia de fuentes personalizada.
* **Variant** — la etiqueta de la variante (por ejemplo, *Size: Medium*).
* **Subscription plan** — la etiqueta de solo lectura del plan que se muestra en las líneas de suscripción.

**Pricing**

* **Price** — el precio actual de la línea.
* **Compare-at price** — el precio original tachado.
* **Savings** — la etiqueta de ahorros (por ejemplo, *Save \$5.00*). Solo Size y Line height — el bold y el color se configuran en el Rich Text Editor de arriba.

**Bundle**

* **Bundle toggle** — el encabezado desplegable que expande la lista de componentes de un bundle.
* **Bundle item title** — el título de cada componente dentro de un bundle.
* **Bundle item variant** — la etiqueta de variante de cada componente del bundle.

Dejar cualquier campo en blanco mantiene el valor predeterminado del elemento.

<Tip>
  Al hacer clic directamente sobre un elemento de texto en la vista previa del carrito, se resalta y se abren automáticamente sus controles en el panel.
</Tip>

<div id="discount-tags-design">
  ### Diseño de las etiquetas de descuento
</div>

La fila Product incluye una sección **Discount tags** en su configuración de Design. Úsala para dar estilo a las píldoras de etiqueta de descuento que aparecen en cada artículo de línea:

| Configuración        | Qué controla                                                   | Predeterminado |
| -------------------- | -------------------------------------------------------------- | -------------- |
| **Background color** | Color de relleno de la píldora de etiqueta de descuento.       | `#F1F1F1`      |
| **Text color**       | Color del texto dentro de la píldora de etiqueta de descuento. | `#585858`      |
| **Border radius**    | Redondeo de esquinas de la píldora de etiqueta de descuento.   | `6px`          |

Estas configuraciones se aplican solo a las etiquetas de descuento de los artículos de línea en el bloque Cart items. Las etiquetas de códigos de descuento en el [bloque Summary](/es/aftersell/cart/summary-block) se estilizan por separado.

<div id="sub-blocks-and-how-they-position">
  ## Los sub-bloques y cómo se posicionan
</div>

Cart items es el único bloque que aloja sub-bloques. **Los sub-bloques se renderizan una vez por línea, dentro de cada fila de producto**, posicionados en relación con la fila Product fijada:

* Los sub-bloques ordenados **antes** de la fila Product aparecen **encima** del contenido del producto en cada línea.
* Los sub-bloques ordenados **después** de la fila Product aparecen **debajo** del contenido del producto en cada línea.

Así, un [Subscription upgrade](/es/aftersell/cart/subscription-upgrade-block) colocado después de la fila Product se muestra debajo de cada línea elegible, no una sola vez al final de toda la lista.

<div id="behavior">
  ## Comportamiento
</div>

* Cuando el carrito no tiene artículos, el cajón cambia al estado vacío y este bloque no se muestra.
* **Se ejecuta un cambio del carrito a la vez.** Mientras una actualización de cantidad o una eliminación está en curso, los controles de la fila se deshabilitan para mantener el carrito consistente, y luego se vuelven a habilitar una vez que el cambio se completa.
* Reducir la cantidad de una línea por debajo de 1 la elimina. Una cantidad que la tienda rechaza (por ejemplo, más allá del inventario disponible) se vuelve a sincronizar con el último valor válido.
* **Los bundles cambian como una unidad.** Ajustar la cantidad en la línea ancla de un bundle escala todo el bundle en una sola operación: si un componente se incluye a razón de 3 por ancla, llevar el ancla de 1 a 2 lleva ese componente a 6. Eliminar el ancla elimina todos los miembros del bundle a la vez.
* **Algunos bundles no pueden cambiar de cantidad.** Si alguno de los componentes de un bundle se incluye a una tasa fraccionaria (digamos, 1.5 por ancla), el control de cantidad de ese bundle se bloquea: los botones +/− y el campo de cantidad quedan deshabilitados, y las cantidades escritas no se aceptan. El bundle aún puede eliminarse.
* **Las líneas de suscripción muestran su plan.** Cuando una línea tiene un plan de venta y el sub-bloque [Subscription upgrade](/es/aftersell/cart/subscription-upgrade-block) está desactivado o no se ha agregado, la fila Product muestra una etiqueta de plan de solo lectura debajo de la variante; por ejemplo, *Delivers every month (save 30%)*. Cuando ese sub-bloque está habilitado, presenta el plan en su propio selector, por lo que la etiqueta de solo lectura se suprime en lugar de duplicarse.

<div id="placement-and-limits">
  ## Ubicación y límites
</div>

* **Región:** cuerpo.
* **Máximo:** 1 por estado del carrito.
* **Estado:** solo carrito con artículos.
* **Bloqueado y agregado de forma predeterminada.** Cart items no puede eliminarse ni ocultarse, solo reposicionarse.

<div id="custom-template">
  ## Plantilla personalizada
</div>

Admite una [plantilla personalizada](/es/aftersell/cart/custom-templates) desde su pestaña Code, que reemplaza el marcado integrado de este bloque con tu JSX. Estas son las props que recibe.

El contenedor **Cart items** no tiene plantilla personalizada. La fila **Product** dentro de él sí, y es la superficie más rica del carrito: tu plantilla se renderiza una vez por línea.

<div id="line-content">
  ### Contenido de la línea
</div>

| Prop               | Tipo                        | Para qué sirve                                                                                                                                                                                                                                               |
| ------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `title`            | `string`                    | Título del producto, como texto plano.                                                                                                                                                                                                                       |
| `variantTitle`     | `string \| null`            | Etiqueta de la variante. `null` para productos de una sola variante y bundles nativos.                                                                                                                                                                       |
| `url`              | `string \| null`            | URL de la página del producto. `null` cuando la línea no debe enlazar hacia afuera.                                                                                                                                                                          |
| `imageUrl`         | `string \| null`            | Imagen de la línea. `null` cuando el producto no tiene ninguna.                                                                                                                                                                                              |
| `quantity`         | `number`                    | Cantidad actual en la línea.                                                                                                                                                                                                                                 |
| `price`            | `string`                    | Precio de la línea, **ya formateado**.                                                                                                                                                                                                                       |
| `compareAtPrice`   | `string \| null`            | El precio anterior tachado, ya formateado. `null` cuando no hay nada que tachar.                                                                                                                                                                             |
| `savingsHtml`      | `string \| null`            | Etiqueta de ahorros como HTML sanitizado. `null` cuando está oculta o no hay ahorro.                                                                                                                                                                         |
| `discountTags`     | `string[]`                  | Títulos de los descuentos en esta línea, p. ej. `['Spring Sale']`. `[]` cuando no hay ninguno.                                                                                                                                                               |
| `sellingPlanLabel` | `string \| null`            | Nombre del plan de suscripción de solo lectura. `null` cuando es una línea de compra única, o cuando el sub-bloque [Subscription upgrade](/es/aftersell/cart/subscription-upgrade-block#custom-template) está renderizando la interfaz del plan en su lugar. |
| `bundle`           | `object \| null`            | Modelo de vista del [bundle](/es/aftersell/cart/sdk-cart-object#bundles) en una línea ancla. `null` en caso contrario.                                                                                                                                       |
| `productId`        | `number`                    | ID del producto de Shopify.                                                                                                                                                                                                                                  |
| `variantId`        | `number`                    | ID de la variante de Shopify.                                                                                                                                                                                                                                |
| `line`             | `AftersellCartLine`         | La [línea del carrito](/es/aftersell/cart/sdk-cart-object#cart-lines) completa, para cualquier cosa que las props anteriores no cubran.                                                                                                                      |
| `formatMoney`      | `(cents: number) => string` | Formatea un monto en unidades menores. Úsalo para los precios que leas de `line`.                                                                                                                                                                            |

<Warning>
  **`price` y `compareAtPrice` son cadenas formateadas; todo en `line` está en centavos.** No hagas aritmética con `price`. Calcula a partir de `line.finalLinePrice` y similares, y luego pasa el resultado por `formatMoney`.
</Warning>

<div id="quantity-and-removal">
  ### Cantidad y eliminación
</div>

| Prop                | Tipo                                             | Para qué sirve                                                                                                                                                                                                                                                          |
| ------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `increment`         | `() => void`                                     | Agrega uno a la línea.                                                                                                                                                                                                                                                  |
| `decrement`         | `() => void`                                     | Quita uno de la línea.                                                                                                                                                                                                                                                  |
| `remove`            | `() => void`                                     | Elimina la línea por completo.                                                                                                                                                                                                                                          |
| `quantityInput`     | `string`                                         | Valor actual para un `<input>` de cantidad controlado. Una cadena, para que los estados de escritura intermedia sobrevivan.                                                                                                                                             |
| `onQuantityInput`   | `(event: Event) => void`                         | Manejador `onInput` para ese campo.                                                                                                                                                                                                                                     |
| `commitQuantity`    | `() => void`                                     | Aplica la cantidad escrita. Conéctalo a `onBlur`.                                                                                                                                                                                                                       |
| `onQuantityKeyDown` | `(event: KeyboardEvent) => void`                 | Manejador `onKeyDown`, para que Enter confirme.                                                                                                                                                                                                                         |
| `busy`              | `boolean`                                        | `true` mientras cualquier mutación del carrito está en curso. Deshabilita tus controles con esto.                                                                                                                                                                       |
| `pending`           | `'increment' \| 'decrement' \| 'remove' \| null` | Qué acción está actualmente en curso, para un indicador de carga específico.                                                                                                                                                                                            |
| `stepperLocked`     | `boolean`                                        | `true` cuando la cantidad no puede cambiarse, porque la línea es un ancla de bundle con un componente incluido a una tasa fraccionaria por ancla. Oculta o deshabilita el control de cantidad: los manejadores integrados ya rechazan los cambios mientras está activo. |

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomTemplate(props) {
  return (
    <div className="cart-external-cart-items__row" style={{ display: 'flex', gap: '12px', opacity: props.busy ? 0.6 : 1 }}>
      {props.imageUrl && <img src={props.imageUrl} alt="" width={64} height={64} />}

      <div style={{ flex: 1 }}>
        {props.url ? <a href={props.url}>{props.title}</a> : <span>{props.title}</span>}
        {props.variantTitle && <div style={{ opacity: 0.6 }}>{props.variantTitle}</div>}
        {props.sellingPlanLabel && <div style={{ opacity: 0.6 }}>{props.sellingPlanLabel}</div>}

        {props.discountTags.map((tag) => (
          <span key={tag} style={{ fontSize: '11px', border: '1px solid', borderRadius: '4px', padding: '1px 5px' }}>
            {tag}
          </span>
        ))}

        {!props.stepperLocked && (
          <div style={{ display: 'flex', alignItems: 'center', gap: '6px', marginTop: '6px' }}>
            <button type="button" onClick={props.decrement} disabled={props.busy}>&minus;</button>
            <input
              value={props.quantityInput}
              onInput={props.onQuantityInput}
              onBlur={props.commitQuantity}
              onKeyDown={props.onQuantityKeyDown}
              size={2}
            />
            <button type="button" onClick={props.increment} disabled={props.busy}>+</button>
            <button type="button" onClick={props.remove} disabled={props.busy}>
              {props.pending === 'remove' ? 'Removing…' : 'Remove'}
            </button>
          </div>
        )}
      </div>

      <div style={{ textAlign: 'right' }}>
        <div>{props.price}</div>
        {props.compareAtPrice && <s style={{ opacity: 0.5 }}>{props.compareAtPrice}</s>}
        {props.savingsHtml && <div dangerouslySetInnerHTML={{ __html: props.savingsHtml }} />}
      </div>
    </div>
  );
}
```

<div id="rendering-a-bundle">
  ### Renderizar un bundle
</div>

En la línea ancla de un bundle, `bundle.children` contiene su contenido. Los componentes nunca aparecen como filas propias, así que si no los renderizas, el comprador no verá lo que hay en el bundle:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomTemplate(props) {
  return (
    <div>
      <div>{props.title} {props.price}</div>

      {props.bundle && (
        <ul style={{ margin: '4px 0 0 12px', fontSize: '12px', opacity: 0.7 }}>
          {props.bundle.children.map((child, i) => (
            <li key={child.key ?? i}>{child.quantity} × {child.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}
```

La `key` de un componente es `null` para un componente de bundle nativo de Shopify, así que recurre al índice como se muestra arriba.

<div id="design">
  ## Diseño
</div>

Dale estilo a este bloque con su sección **Design** en el panel de configuración. Estas son anulaciones por bloque que se superponen a tu diseño global y recurren a él cuando están en blanco.

¿Qué son las configuraciones de diseño? Obtén más información aquí: [Configuraciones de diseño](/es/aftersell/cart/design-settings).
