返品・交換リクエストフォーム
This is a demo page for a return/exchange request form for Shopify. It supports inputting order number, order date, and product name, selecting either return (refund) or exchange, and choosing a reason category (e.g., damaged/defective product, incorrect delivery, wrong size, different from image). Multiple product condition photos can be attached via drag-and-drop, with thumbnail previews. A checkbox for policy agreement is also included. This will streamline customer support operations and improve the quality of return and exchange processing. You can use it immediately by copying the HTML, CSS, and JavaScript.
プレビュー
※プレビューのため送信ボタンは押せません
コード
HTML
<h1>返品・交換リクエスト</h1>
<p class="form-description">商品の返品・交換をご希望の場合は、以下のフォームよりお申し込みください。</p>
<div class="note">
※ 商品到着後7日以内にお申し込みください。<br>
※ お客様都合の返品は未使用・未開封の商品に限ります。
</div>
<form action="#" method="POST" enctype="multipart/form-data">
<div class="form-row">
<div class="form-group">
<label for="name" class="required">お名前</label>
<input type="text" id="name" name="name" required autocomplete="name">
</div>
<div class="form-group">
<label for="email" class="required">メールアドレス</label>
<input type="email" id="email" name="email" required autocomplete="email">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="order_number" class="required">注文番号</label>
<input type="text" id="order_number" name="order_number" placeholder="例: #12345" required>
</div>
<div class="form-group">
<label for="order_date">ご注文日</label>
<input type="date" id="order_date" name="order_date">
</div>
</div>
<div class="form-group">
<label for="product_name" class="required">商品名</label>
<input type="text" id="product_name" name="product_name" placeholder="返品・交換をご希望の商品名" required>
</div>
<div class="form-group">
<label class="required">ご希望の対応</label>
<div class="radio-group">
<label class="radio-item">
<input type="radio" name="request_type" value="return" required>
<span>返品(返金)</span>
</label>
<label class="radio-item">
<input type="radio" name="request_type" value="exchange">
<span>交換</span>
</label>
</div>
</div>
<div class="form-group">
<label for="reason" class="required">理由</label>
<select id="reason" name="reason" required>
<option value="">選択してください</option>
<optgroup label="商品の不具合">
<option value="damaged">商品が破損していた</option>
<option value="defective">商品に欠陥がある</option>
<option value="wrong_item">注文と異なる商品が届いた</option>
</optgroup>
<optgroup label="お客様都合">
<option value="size">サイズが合わない</option>
<option value="color">色・イメージが違った</option>
<option value="duplicate">重複して注文した</option>
<option value="other_customer">その他</option>
</optgroup>
</select>
</div>
<div class="form-group">
<label for="detail" class="required">詳細</label>
<textarea id="detail" name="detail" placeholder="具体的な状況をご記入ください(破損箇所、交換希望のサイズ・色など)" required></textarea>
</div>
<div class="form-group">
<label>商品の状態がわかる写真</label>
<div class="drop-zone">
<input type="file" name="images[]" accept="image/*" multiple class="file-input">
<div class="drop-zone-text">画像をドラッグ&ドロップ、またはクリックして選択</div>
<div class="drop-zone-hint">複数選択可・1ファイル最大10MB(jpg, png, webp)</div>
</div>
<ul class="previews"></ul>
</div>
<div class="form-group">
<label class="checkbox-item">
<input type="checkbox" name="agree" required>
<span>返品・交換ポリシーに同意します</span>
</label>
</div>
<button type="submit" class="btn-submit">送信する</button>
</form>
CSS
.form-description {
color: #666;
margin-bottom: 32px;
font-size: 14px;
}
.form-group {
margin-bottom: 24px;
}
label {
display: block;
font-weight: 500;
margin-bottom: 8px;
font-size: 14px;
}
.required::after {
content: "*";
color: #e53935;
margin-left: 4px;
}
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="date"],
select,
textarea {
width: 100%;
padding: 12px 16px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 16px;
transition: border-color 0.2s, box-shadow 0.2s;
box-sizing: border-box;
}
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37,99,235,0.1);
}
textarea {
min-height: 120px;
resize: vertical;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 540px) {
.form-row {
grid-template-columns: 1fr;
}
}
.radio-group {
display: flex;
gap: 24px;
flex-wrap: wrap;
}
.radio-item {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
.radio-item input[type="radio"] {
width: 18px;
height: 18px;
accent-color: #2563eb;
}
.checkbox-item {
display: flex;
align-items: flex-start;
gap: 8px;
cursor: pointer;
}
.checkbox-item input[type="checkbox"] {
width: 18px;
height: 18px;
margin-top: 2px;
accent-color: #2563eb;
}
/* ドロップゾーン(画像添付) */
.drop-zone {
border: 2px dashed #ddd;
border-radius: 8px;
padding: 32px;
text-align: center;
cursor: pointer;
transition: border-color 0.2s, background 0.2s;
position: relative;
}
.drop-zone:hover,
.drop-zone.is-dragover {
border-color: #2563eb;
background: #f8fafc;
}
.drop-zone .file-input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
.drop-zone-text {
color: #666;
font-size: 14px;
}
.drop-zone-hint {
color: #999;
font-size: 12px;
margin-top: 8px;
}
/* プレビューリスト */
.previews {
list-style: none;
padding: 0;
margin: 12px 0 0;
}
.previews .preview {
padding: 8px 12px;
background: #f5f5f5;
border-radius: 4px;
font-size: 13px;
color: #333;
margin-bottom: 6px;
}
.btn-submit {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 14px 32px;
background: #2563eb;
color: #fff;
border: none;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s, transform 0.1s;
}
.btn-submit:hover {
background: #1d4ed8;
}
.btn-submit:active {
transform: translateY(1px);
}
.note {
background: #fef3c7;
border-left: 4px solid #f59e0b;
padding: 12px 16px;
margin-bottom: 24px;
font-size: 14px;
color: #92400e;
}
JavaScript
const form = document.querySelector("form");
const fileInput = form.querySelector(".file-input");
const dropZone = form.querySelector(".drop-zone");
const previewList = form.querySelector(".previews");
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
let selectedFiles = [];
function addFiles(list){
for(const file of list){
if(!file.type.startsWith("image/")) { console.warn("画像以外は不可:", file.name); continue; }
if(file.size > MAX_FILE_SIZE) { console.warn("10MB超過:", file.name); continue; }
selectedFiles.push(file);
}
const dt = new DataTransfer();
selectedFiles.forEach(f => dt.items.add(f));
fileInput.files = dt.files;
previewList.innerHTML = "";
selectedFiles.forEach(f => {
const li = document.createElement("li");
li.className = "preview";
li.textContent = `${f.name} (${(f.size/1024/1024).toFixed(1)} MB)`;
previewList.appendChild(li);
});
}
// 誤ドロップ遷移防止
addEventListener("dragover", e => e.preventDefault());
addEventListener("drop", e => e.preventDefault());
// D&D
["dragenter","dragover"].forEach(ev => {
dropZone.addEventListener(ev, e => { e.preventDefault(); dropZone.classList.add("is-dragover"); });
});
["dragleave","drop"].forEach(ev => {
dropZone.addEventListener(ev, e => { e.preventDefault(); dropZone.classList.remove("is-dragover"); });
});
dropZone.addEventListener("drop", e => addFiles(e.dataTransfer.files));
fileInput.addEventListener("change", e => addFiles(e.target.files));