12 Ecommerce Email Templates / Lifecycle

Free React Email Abandoned Cart Template

Build an abandoned cart recovery email with React Email. Line items, totals and objection handling — customize and export TSX for free.

Sample subject
You left two bags in the cart
Format
React Email TSX · Free
Abandoned Cart React Email template preview

Template details

What this abandoned cart template includes

Build an abandoned cart recovery email with React Email. Line items, totals and objection handling — customize and export TSX for free. The source is standard TypeScript and React Email, so it can be sent with Resend or rendered to HTML for another email provider.

  • Production-ready lifecycle email structure
  • Editable in the visual React Email playground
  • Free TSX source for personal and commercial projects

How to use it

  1. 1. Customize the copy and styles in the playground above.
  2. 2. Export or copy the typed TSX source.
  3. 3. Pass dynamic props and send it from a server route with your email provider.
Follow the Resend and Next.js implementation guide

React Email TSX source

Free for personal, commercial, and client projects under the site license.

View full source code
import * as React from 'react';

import {
  Band,
  Brand,
  Centered,
  Display,
  EmailLayout,
  Eyebrow,
  LineItem,
  LineItems,
  Note,
  NumberedList,
  OutlineButton,
  Prose,
  SectionTitle,
  Spacer,
  TotalRow,
  Totals,
} from './components';

export interface AbandonedCartEmailProps {
  brand?: Brand;
  subject?: string;
  preview?: string;
  eyebrow?: string;
  headline?: React.ReactNode;
  intro?: string;
  items?: LineItem[];
  totals?: TotalRow[];
  cta?: { label: string; href: string };
  /** The line under the button — how long the cart is held. */
  hold?: string;
  /** Objection handling, on the deep ground. */
  reasons?: {
    eyebrow: string;
    title: string;
    items: string[];
  };
  signoff?: string;
}

/**
 * Abandoned cart — the cart itemised and totalled, the reasons to finish it,
 * and an offer to fix whatever stopped them. No countdown, no manufactured
 * scarcity beyond what is true.
 */
export function AbandonedCartEmail({
  brand,
  subject = 'You left two bags in the cart',
  preview = 'We held them. We are not saving them forever, but we held them.',
  eyebrow = 'Still warm',
  headline = (
    <>
      Your cart is
      <br />
      getting stale
    </>
  ),
  intro = 'Nothing has been charged. Everything is still in stock, for now. Solstice is down to the last of the first roast.',
  items = [
    {
      image: {
        src: 'https://images.unsplash.com/photo-1559056199-641a0ac8b55e?w=168&h=168&q=75&auto=format&fit=crop',
        alt: 'Solstice',
      },
      name: 'Solstice',
      meta: '12 oz · Whole bean',
      quantity: 1,
      price: '$21.00',
    },
    {
      image: {
        src: 'https://images.unsplash.com/photo-1447933601403-0c6688de566e?w=168&h=168&q=75&auto=format&fit=crop',
        alt: 'Night Shift',
      },
      name: 'Night Shift',
      meta: '12 oz · Ground for filter',
      quantity: 2,
      price: '$38.00',
    },
  ],
  totals = [
    { label: 'Subtotal', value: '$59.00' },
    { label: 'Shipping', value: 'Free over $45' },
    { label: 'Total', value: '$59.00', emphasis: true },
  ],
  cta = { label: 'Finish checkout', href: '#' },
  hold = 'Cart held until Thursday.',
  reasons = {
    eyebrow: 'If you were hesitating',
    title: 'Three reasons to just do it',
    items: [
      'Free shipping over $45. You are already there.',
      'Roasted the morning it ships, never before.',
      'If you do not like it, we replace it. No form, no photo of the beans.',
    ],
  },
  signoff = 'Changed your mind about the grind? Reply and we will fix it before it ships.',
}: AbandonedCartEmailProps = {}) {
  return (
    <EmailLayout brand={brand} subject={subject} preview={preview}>
      <Band padding="36px 40px 28px" align="center">
        <Eyebrow>{eyebrow}</Eyebrow>
        <Display>{headline}</Display>
        <Prose margin="16px auto 0" maxWidth={400}>
          {intro}
        </Prose>
      </Band>

      <Band padding="0 40px 34px">
        <LineItems items={items} leadingRule />
        <Totals rows={totals} />
        <Spacer height={22} />
        <Centered>
          <OutlineButton href={cta.href} align="center">
            {cta.label}
          </OutlineButton>
          {hold ? <Note margin="10px 0 0">{hold}</Note> : null}
        </Centered>
      </Band>

      <Band tone="dark">
        <Centered>
          <Eyebrow tone="dark">{reasons.eyebrow}</Eyebrow>
          <SectionTitle tone="dark">{reasons.title}</SectionTitle>
        </Centered>
        <Spacer height={10} />
        <NumberedList items={reasons.items} />
      </Band>

      <Band tone="paper" padding="24px 40px 28px">
        <Centered>
          <Prose size={14} margin="0 0 16px">
            {signoff}
          </Prose>
        </Centered>
      </Band>
    </EmailLayout>
  );
}

export default AbandonedCartEmail;

Related templates

More from 12 Ecommerce Email Templates.

View the complete bundle