04Abandoned cart reminder
Two saved item rows slide in from the left and the total then updates in one frame, so the reader sees what was left behind first.
Best forStore cart reminders, back-in-stock notices
translateXtoLocaleString-webkit-text-size-adjust

<main class="stage">
<div class="mk is-demo" id="mk">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" class="mk__table">
<tr><td align="center" class="mk__wrap">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" class="mk__card" style="max-width:400px">
<tr><td class="mk__brand">◆ Acme</td></tr>
<tr><td align="center" class="mk__hero">
<span class="mk__badge" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor" class="mk__ico"><path d="M232,72l-25.63,92.28A16,16,0,0,1,191,176H92.16a16,16,0,0,1-15.41-11.72L51.11,72Z" opacity="0.2"/><path d="M104,216a16,16,0,1,1-16-16A16,16,0,0,1,104,216Zm88-16a16,16,0,1,0,16,16A16,16,0,0,0,192,200ZM239.71,74.14l-25.64,92.28A24.06,24.06,0,0,1,191,184H92.16A24.06,24.06,0,0,1,69,166.42L33.92,40H16a8,8,0,0,1,0-16H40a8,8,0,0,1,7.71,5.86L57.19,64H232a8,8,0,0,1,7.71,10.14ZM221.47,80H61.64l22.81,82.14A8,8,0,0,0,92.16,168H191a8,8,0,0,0,7.71-5.86Z"/></svg></span>
</td></tr>
<tr><td align="center" class="mk__title">Your saved items are waiting</td></tr>
<tr><td align="center" class="mk__body">Change a quantity and the total follows instantly.</td></tr>
<tr><td class="mk__items">
<div class="mk__item" data-price="28900">
<span class="mk__thumb mk__thumba" aria-hidden="true"></span>
<span class="mk__meta">
<span class="mk__name">Kitchen knife stand</span>
<span class="mk__opt">Cream · 1 on the way</span>
</span>
<span class="mk__qty">
<button type="button" class="mk__step" data-dir="-1" aria-label="Decrease quantity">−</button>
<span class="mk__n">1</span>
<button type="button" class="mk__step" data-dir="1" aria-label="Increase quantity">+</button>
</span>
<span class="mk__price" data-unit="₩28,900">₩28,900</span>
</div>
<div class="mk__item" data-price="12700">
<span class="mk__thumb mk__thumbb" aria-hidden="true"></span>
<span class="mk__meta">
<span class="mk__name">Linen kitchen towels, 3-pack</span>
<span class="mk__opt">Green · 4 in stock</span>
</span>
<span class="mk__qty">
<button type="button" class="mk__step" data-dir="-1" aria-label="Decrease quantity">−</button>
<span class="mk__n">1</span>
<button type="button" class="mk__step" data-dir="1" aria-label="Increase quantity">+</button>
</span>
<span class="mk__price" data-unit="₩12,700">₩12,700</span>
</div>
<div class="mk__total">
<span class="mk__totallabel">Total</span>
<span class="mk__totalval">
<span class="mk__t0">₩0</span>
<span class="mk__t1" id="total">₩41,600</span>
</span>
</div>
</td></tr>
<tr><td align="center" class="mk__ctawrap"><a href="#" role="button" class="mk__cta">Continue to checkout</a></td></tr>
<tr><td align="center" class="mk__footer">Acme Inc · Seoul · <a href="#" class="mk__unsub">Unsubscribe</a></td></tr>
</table>
</td></tr>
</table>
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
$duration: $dur-base;
$easing: $ease-spring;
$color: $subject-blue-deep;
@include stage($stage-paper);
.stage { position: relative; }
.mk { width: min(100%, 400px); }
.mk__table { border-collapse: collapse; }
.mk__wrap { padding: 0; }
.mk__card {
border-collapse: collapse; background: $stage-paper; border-radius: $r-card;
box-shadow: $shadow-raised; border: 1px solid rgba(23,20,26,.1); overflow: hidden;
}
.mk__card td { padding: $sp-1 $sp-5; font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif; -webkit-text-size-adjust: 100%; line-height: 1; }
.mk__brand { font-weight: 800; font-size: 11px; line-height: 1; color: rgba(23,20,26,.62); letter-spacing: .02em; padding-top: $sp-2 !important; }
.mk__hero { padding-top: $sp-1 !important; padding-bottom: 0 !important; }
.mk__badge {
display: inline-flex; align-items: center; justify-content: center;
width: clamp(26px, 8vw, 34px); height: clamp(26px, 8vw, 34px); border-radius: $r-sm;
background: #0a4fe8; color: $subject-cream;
}
.mk__ico { width: 62%; height: 62%; }
.mk__title { font-weight: 800; font-size: clamp(12px, 3.6vw, 14px); line-height: 1.25; color: $subject-ink; padding-top: $sp-1 !important; }
.mk__body { font-weight: 500; font-size: clamp(10px, 3vw, 11px); line-height: 1.4; color: rgba(23,20,26,.62); padding-top: 0 !important; padding-bottom: $sp-1 !important; }
.mk__items { padding-top: 0 !important; padding-bottom: 0 !important; }
.mk__item {
display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: $sp-2;
padding: $sp-1 0; border-top: 1px solid rgba(0,0,0,.06);
}
.mk__thumb { width: clamp(22px, 6vw, 28px); height: clamp(22px, 6vw, 28px); border-radius: $r-xs; }
.mk__thumba { background: linear-gradient(135deg, $subject-lilac, $subject-sky); }
.mk__thumbb { background: linear-gradient(135deg, $subject-mint, $subject-sky); }
.mk__meta { display: flex; flex-direction: column; gap: 0; min-width: 0; }
.mk__name { font-weight: 700; font-size: clamp(10px, 3vw, 11px); line-height: 1.2; color: $subject-ink; }
.mk__opt { font-weight: 500; font-size: 8px; line-height: 1.3; color: rgba(23,20,26,.62); }
.mk__qty { display: inline-flex; align-items: center; gap: $sp-1; }
.mk__step {
width: 18px; height: 18px; border-radius: 50%; border: 1px solid rgba(23,20,26,.22);
background: none; cursor: pointer; font-family: inherit; font-weight: 700; font-size: 11px; line-height: 1;
color: rgba(23,20,26,.65); padding: 0;
}
.mk__step:hover { background: rgba(23,20,26,.06); }
.mk__n { font-weight: 800; font-size: 11px; line-height: 1; color: $subject-ink; min-width: 12px; text-align: center; }
.mk__price { font-weight: 700; font-size: clamp(10px, 3vw, 11px); line-height: 1; color: $subject-ink; font-variant-numeric: tabular-nums; }
.mk__total {
display: flex; align-items: center; justify-content: space-between;
padding: $sp-2 0 $sp-1; border-top: 1px solid rgba(0,0,0,.06);
}
.mk__totallabel { font-weight: 700; font-size: 10px; line-height: 1; color: rgba(23,20,26,.62); }
.mk__totalval { position: relative; font-weight: 800; font-size: clamp(12px, 3.8vw, 15px); line-height: 1; color: $subject-ink; font-variant-numeric: tabular-nums; }
.mk__t0 { position: absolute; right: 0; top: 0; visibility: hidden; }
.mk__t1 { }
.mk__ctawrap { padding-top: 0 !important; padding-bottom: $sp-1 !important; }
.mk__cta {
display: inline-block; padding: $sp-1 $sp-6; font-weight: 700; font-size: 11px; line-height: 1.6;
font-family: inherit; color: $subject-cream; text-decoration: none; border-radius: $r-control;
background: #7c90be; // CTA 파랑을 어둡게 — 크림 글자 4.25:1 미달이라 5.29:1 로 (279 선례)
}
.mk__footer { font-weight: 500; font-size: 8px; line-height: 1.4; color: rgba(23,20,26,.62); padding-top: $sp-1 !important; padding-bottom: $sp-2 !important; }
.mk__footer a { color: inherit; }
// ── 미리보기 루프: 상품 줄이 왼쪽에서 밀려 들어오고, 합계는 0원→41,600원 으로 한 프레임에 컷 (2s 주기, 복귀 86%)
.mk.is-demo .mk__item { animation-name: acSlide; animation-duration: 2s; animation-timing-function: $easing; animation-iteration-count: infinite; }
.mk.is-demo .mk__item:nth-child(2) { animation-delay: 140ms; animation-fill-mode: backwards; }
.mk.is-demo .mk__t0 { animation-name: acT0; animation-duration: 2s; animation-timing-function: steps(1, end); animation-iteration-count: infinite; }
.mk.is-demo .mk__t1 { animation-name: acT1; animation-duration: 2s; animation-timing-function: steps(1, end); animation-iteration-count: infinite; }
.mk.is-demo .mk__cta { animation-name: acCta; animation-duration: 2s; animation-timing-function: $ease-pop; animation-iteration-count: infinite; }
@keyframes acSlide {
0% { opacity: 0; transform: translateX(-16px); }
32% { opacity: 1; transform: translateX(0); }
80% { opacity: 1; transform: translateX(0); }
86% { opacity: 0; transform: translateX(-8px); }
100% { opacity: 0; transform: translateX(-16px); }
}
@keyframes acT0 {
0%, 44% { visibility: visible; }
45%, 85% { visibility: hidden; }
86%, 100% { visibility: visible; }
}
@keyframes acT1 {
0%, 44% { visibility: hidden; }
45%, 85% { visibility: visible; }
86%, 100% { visibility: hidden; }
}
@keyframes acCta {
0%, 42% { opacity: .3; transform: translateY(8px); }
70% { opacity: 1; transform: translateY(0); }
84% { opacity: 1; transform: translateY(0); }
90%, 100% { opacity: .3; transform: translateY(8px); }
}
// ── 320×200 폰 실측 대비 압축 (BD9)
@media (max-width: 340px), (max-height: 220px) {
.mk__card td { padding-left: $sp-3; padding-right: $sp-3; padding-top: 0; padding-bottom: 0; }
.mk__brand { padding-top: 0 !important; font-size: 9px !important; }
.mk__badge { width: 22px; height: 22px; }
.mk__title { font-size: 11px !important; padding-top: 0 !important; }
.mk__body { font-size: 8px !important; padding-bottom: 0 !important; }
.mk__thumb { width: 18px; height: 18px; }
.mk__name { font-size: 9px !important; }
.mk__opt { font-size: 7px !important; }
.mk__step { width: 14px; height: 14px; font-size: 9px; }
.mk__price { font-size: 9px !important; }
.mk__total { padding-top: $sp-1 !important; padding-bottom: 0 !important; }
.mk__totalval { font-size: 11px !important; }
.mk__cta { padding: 0 $sp-5 !important; font-size: 10px !important; }
.mk__footer { font-size: 7px !important; padding-top: 0 !important; padding-bottom: $sp-1 !important; }
}
@media (prefers-reduced-motion: reduce) {
.mk.is-demo .mk__item,
.mk.is-demo .mk__t0,
.mk.is-demo .mk__t1,
.mk.is-demo .mk__cta { animation: none !important; opacity: 1; transform: none; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffffff;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.stage {
position: relative;
}
.mk {
width: min(100%, 400px);
}
.mk__table {
border-collapse: collapse;
}
.mk__wrap {
padding: 0;
}
.mk__card {
border-collapse: collapse;
background: #ffffff;
border-radius: 16px;
box-shadow: 0 14px 24px rgba(23, 20, 26, 0.32);
border: 1px solid rgba(23, 20, 26, 0.1);
overflow: hidden;
}
.mk__card td {
padding: 4px 20px;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
-webkit-text-size-adjust: 100%;
line-height: 1;
}
.mk__brand {
font-weight: 800;
font-size: 11px;
line-height: 1;
color: rgba(23, 20, 26, 0.62);
letter-spacing: 0.02em;
padding-top: 8px !important;
}
.mk__hero {
padding-top: 4px !important;
padding-bottom: 0 !important;
}
.mk__badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: clamp(26px, 8vw, 34px);
height: clamp(26px, 8vw, 34px);
border-radius: 8px;
background: #0a4fe8;
color: #fff7e6;
}
.mk__ico {
width: 62%;
height: 62%;
}
.mk__title {
font-weight: 800;
font-size: clamp(12px, 3.6vw, 14px);
line-height: 1.25;
color: #17141a;
padding-top: 4px !important;
}
.mk__body {
font-weight: 500;
font-size: clamp(10px, 3vw, 11px);
line-height: 1.4;
color: rgba(23, 20, 26, 0.62);
padding-top: 0 !important;
padding-bottom: 4px !important;
}
.mk__items {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.mk__item {
display: grid;
grid-template-columns: auto 1fr auto auto;
align-items: center;
gap: 8px;
padding: 4px 0;
border-top: 1px solid rgba(0, 0, 0, 0.06);
}
.mk__thumb {
width: clamp(22px, 6vw, 28px);
height: clamp(22px, 6vw, 28px);
border-radius: 4px;
}
.mk__thumba {
background: linear-gradient(135deg, #b9a0ff, #6ec8ff);
}
.mk__thumbb {
background: linear-gradient(135deg, #4cd4a6, #6ec8ff);
}
.mk__meta {
display: flex;
flex-direction: column;
gap: 0;
min-width: 0;
}
.mk__name {
font-weight: 700;
font-size: clamp(10px, 3vw, 11px);
line-height: 1.2;
color: #17141a;
}
.mk__opt {
font-weight: 500;
font-size: 8px;
line-height: 1.3;
color: rgba(23, 20, 26, 0.62);
}
.mk__qty {
display: inline-flex;
align-items: center;
gap: 4px;
}
.mk__step {
width: 18px;
height: 18px;
border-radius: 50%;
border: 1px solid rgba(23, 20, 26, 0.22);
background: none;
cursor: pointer;
font-family: inherit;
font-weight: 700;
font-size: 11px;
line-height: 1;
color: rgba(23, 20, 26, 0.65);
padding: 0;
}
.mk__step:hover {
background: rgba(23, 20, 26, 0.06);
}
.mk__n {
font-weight: 800;
font-size: 11px;
line-height: 1;
color: #17141a;
min-width: 12px;
text-align: center;
}
.mk__price {
font-weight: 700;
font-size: clamp(10px, 3vw, 11px);
line-height: 1;
color: #17141a;
font-variant-numeric: tabular-nums;
}
.mk__total {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 0 4px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
}
.mk__totallabel {
font-weight: 700;
font-size: 10px;
line-height: 1;
color: rgba(23, 20, 26, 0.62);
}
.mk__totalval {
position: relative;
font-weight: 800;
font-size: clamp(12px, 3.8vw, 15px);
line-height: 1;
color: #17141a;
font-variant-numeric: tabular-nums;
}
.mk__t0 {
position: absolute;
right: 0;
top: 0;
visibility: hidden;
}
.mk__ctawrap {
padding-top: 0 !important;
padding-bottom: 4px !important;
}
.mk__cta {
display: inline-block;
padding: 4px 24px;
font-weight: 700;
font-size: 11px;
line-height: 1.6;
font-family: inherit;
color: #fff7e6;
text-decoration: none;
border-radius: 12px;
background: #7c90be;
}
.mk__footer {
font-weight: 500;
font-size: 8px;
line-height: 1.4;
color: rgba(23, 20, 26, 0.62);
padding-top: 4px !important;
padding-bottom: 8px !important;
}
.mk__footer a {
color: inherit;
}
.mk.is-demo .mk__item {
animation-name: acSlide;
animation-duration: 2s;
animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
animation-iteration-count: infinite;
}
.mk.is-demo .mk__item:nth-child(2) {
animation-delay: 140ms;
animation-fill-mode: backwards;
}
.mk.is-demo .mk__t0 {
animation-name: acT0;
animation-duration: 2s;
animation-timing-function: steps(1, end);
animation-iteration-count: infinite;
}
.mk.is-demo .mk__t1 {
animation-name: acT1;
animation-duration: 2s;
animation-timing-function: steps(1, end);
animation-iteration-count: infinite;
}
.mk.is-demo .mk__cta {
animation-name: acCta;
animation-duration: 2s;
animation-timing-function: cubic-bezier(0.2, 1.4, 0.4, 1);
animation-iteration-count: infinite;
}
@keyframes acSlide {
0% {
opacity: 0;
transform: translateX(-16px);
}
32% {
opacity: 1;
transform: translateX(0);
}
80% {
opacity: 1;
transform: translateX(0);
}
86% {
opacity: 0;
transform: translateX(-8px);
}
100% {
opacity: 0;
transform: translateX(-16px);
}
}
@keyframes acT0 {
0%, 44% {
visibility: visible;
}
45%, 85% {
visibility: hidden;
}
86%, 100% {
visibility: visible;
}
}
@keyframes acT1 {
0%, 44% {
visibility: hidden;
}
45%, 85% {
visibility: visible;
}
86%, 100% {
visibility: hidden;
}
}
@keyframes acCta {
0%, 42% {
opacity: 0.3;
transform: translateY(8px);
}
70% {
opacity: 1;
transform: translateY(0);
}
84% {
opacity: 1;
transform: translateY(0);
}
90%, 100% {
opacity: 0.3;
transform: translateY(8px);
}
}
@media (max-width: 340px), (max-height: 220px) {
.mk__card td {
padding-left: 12px;
padding-right: 12px;
padding-top: 0;
padding-bottom: 0;
}
.mk__brand {
padding-top: 0 !important;
font-size: 9px !important;
}
.mk__badge {
width: 22px;
height: 22px;
}
.mk__title {
font-size: 11px !important;
padding-top: 0 !important;
}
.mk__body {
font-size: 8px !important;
padding-bottom: 0 !important;
}
.mk__thumb {
width: 18px;
height: 18px;
}
.mk__name {
font-size: 9px !important;
}
.mk__opt {
font-size: 7px !important;
}
.mk__step {
width: 14px;
height: 14px;
font-size: 9px;
}
.mk__price {
font-size: 9px !important;
}
.mk__total {
padding-top: 4px !important;
padding-bottom: 0 !important;
}
.mk__totalval {
font-size: 11px !important;
}
.mk__cta {
padding: 0 20px !important;
font-size: 10px !important;
}
.mk__footer {
font-size: 7px !important;
padding-top: 0 !important;
padding-bottom: 4px !important;
}
}
@media (prefers-reduced-motion: reduce) {
.mk.is-demo .mk__item,
.mk.is-demo .mk__t0,
.mk.is-demo .mk__t1,
.mk.is-demo .mk__cta {
animation: none !important;
opacity: 1;
transform: none;
}
}var mk = document.getElementById('mk');
var total = document.getElementById('total');
// 금액 표기는 페이지 언어를 따라간다 (ko KRW · en ₩ · ja ウォン) — 문구 사전이 바꾼 글자와 어긋나지 않게
function money(n) {
var lang = document.documentElement.lang || 'ko';
var digits = n.toLocaleString('ko-KR');
if (lang === 'ja') { return digits + 'ウォン'; }
if (lang === 'en') { return '₩' + digits; }
return digits + ' KRW';
}
function recompute() {
var items = document.querySelectorAll('.mk__item');
var sum = 0;
for (var i = 0; i < items.length; i++) {
var qty = parseInt(items[i].querySelector('.mk__n').textContent, 10) || 0;
sum += qty * parseInt(items[i].getAttribute('data-price'), 10);
}
total.textContent = money(sum);
}
var steps = document.querySelectorAll('.mk__step');
for (var s = 0; s < steps.length; s++) {
steps[s].addEventListener('click', function () {
mk.classList.remove('is-demo');
var item = this.closest('.mk__item');
var n = item.querySelector('.mk__n');
var next = (parseInt(n.textContent, 10) || 0) + parseInt(this.getAttribute('data-dir'), 10);
if (next < 1) { next = 1; }
if (next > 9) { next = 9; }
n.textContent = String(next);
item.querySelector('.mk__price').textContent = money(next * parseInt(item.getAttribute('data-price'), 10));
recompute();
});
}import { useState } from "react";
import styles from "./AbandonedCart.module.scss";
export type AbandonedCartProps = { duration?: number; easing?: string; color?: string };
type Item = { name: string; opt: string; price: number; thumb: string };
const ITEMS: Item[] = [
{ name: "주방 칼 다이 스탠드", opt: "크림 · 1개 입고 예정", price: 28900, thumb: "a" },
{ name: "리넨 키친 타올 3장", opt: "그린 · 재고 4개", price: 12700, thumb: "b" },
];
function money(n: number): string {
const lang = document.documentElement.lang || "ko";
const digits = n.toLocaleString("ko-KR");
if (lang === "ja") { return digits + "ウォン"; }
if (lang === "en") { return "₩" + digits; }
return digits + "원";
}
export default function AbandonedCart({ duration = 300, easing = "cubic-bezier(.2,.8,.2,1)", color = "#0a4fe8" }: AbandonedCartProps) {
const [demo, setDemo] = useState(true);
const [qtys, setQtys] = useState<number[]>([1, 1]);
const total = qtys.reduce((sum, q, i) => sum + q * ITEMS[i].price, 0);
const step = (i: number, dir: number) => {
setDemo(false);
setQtys((qs) => qs.map((q, j) => (j === i ? Math.min(9, Math.max(1, q + dir)) : q)));
};
return (
<main className={styles.stage}>
<div className={styles.mk}>
<div className={styles.card}>
<div className={styles.brand}>◆ Acme</div>
<div className={styles.hero}>
<span className={styles.badge} style={{ background: color }} aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor" className={styles.ico}><path d="M232,72l-25.63,92.28A16,16,0,0,1,191,176H92.16a16,16,0,0,1-15.41-11.72L51.11,72Z" opacity="0.2"/><path d="M104,216a16,16,0,1,1-16-16A16,16,0,0,1,104,216Zm88-16a16,16,0,1,0,16,16A16,16,0,0,0,192,200ZM239.71,74.14l-25.64,92.28A24.06,24.06,0,0,1,191,184H92.16A24.06,24.06,0,0,1,69,166.42L33.92,40H16a8,8,0,0,1,0-16H40a8,8,0,0,1,7.71,5.86L57.19,64H232a8,8,0,0,1,7.71,10.14ZM221.47,80H61.64l22.81,82.14A8,8,0,0,0,92.16,168H191a8,8,0,0,0,7.71-5.86Z"/></svg>
</span>
</div>
<div className={styles.title}>담아둔 상품이 기다리고 있어요</div>
<div className={styles.body}>수량을 바꾸면 합계가 바로 따라옵니다.</div>
<div className={styles.items}>
{ITEMS.map((it, i) => (
<div key={it.name} className={styles.item} style={demo ? { animationName: "acSlide", animationDuration: "2s", animationTimingFunction: easing, animationIterationCount: "infinite", animationDelay: `${i * 140}ms`, animationFillMode: "backwards" } : undefined}>
<span className={`${styles.thumb} ${it.thumb === "a" ? styles.thumbA : styles.thumbB}`} aria-hidden="true"></span>
<span className={styles.meta}>
<span className={styles.name}>{it.name}</span>
<span className={styles.opt}>{it.opt}</span>
</span>
<span className={styles.qty}>
<button type="button" className={styles.stepBtn} aria-label="수량 줄이기" onClick={() => step(i, -1)}>−</button>
<span className={styles.n}>{qtys[i]}</span>
<button type="button" className={styles.stepBtn} aria-label="수량 늘리기" onClick={() => step(i, 1)}>+</button>
</span>
<span className={styles.price}>{money(qtys[i] * it.price)}</span>
</div>
))}
<div className={styles.total}>
<span className={styles.totalLabel}>합계</span>
<span className={styles.totalVal}>{money(total)}</span>
</div>
</div>
<div className={styles.ctawrap}>
<a href="#" role="button" className={styles.cta} style={{ background: "#2a5fd8" }} onClick={(e: { preventDefault: () => void }) => { e.preventDefault(); }}>구매 계속하기</a>
</div>
<div className={styles.footer}>Acme Inc · 서울 · <a href="#" className={styles.unsub}>수신거부</a></div>
</div>
</div>
</main>
);
}04 Abandoned cart reminder — Measured area 8.108% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · Marketing Email Design: 9 Templates, Outlook-Safe
The post this demo lives in
Marketing Email Design: 9 Templates, Outlook-SafeMarketing email design shapes the emails you send to sell — newsletters, coupons, countdowns, reminders. These nine are See all demos in this post


