汎用メールフォーム画像添付付き
This is a demo page for a generic contact form for Shopify. The image attachment feature supports drag-and-drop and allows multiple files to be selected simultaneously (max 50MB per file). Attached images are displayed as thumbnails for preview and can be checked before sending. With a simple structure of Name, Email Address, Subject, and Inquiry Details, it is ideal for product inquiries with photos or for receiving bug reports. You can use it immediately by copying the HTML, CSS, and JavaScript.
プレビュー
※プレビューのため送信ボタンは押せません
コード
HTML
<h1>お問い合わせ</h1>
<label>お名前<span style="color:red">*</span>
<input type="text" name="name" required autocomplete="name">
</label>
<label>メールアドレス<span style="color:red">*</span>
<input type="email" name="email" required autocomplete="email">
</label>
<label>件名
<input type="text" name="subject">
</label>
<label>お問い合わせ内容<span style="color:red">*</span>
<textarea name="message" rows="6" required></textarea>
</label>
<div class="drop-zone" tabindex="0">
<input class="file-input" type="file" name="images[]" accept="image/*" multiple>
<div>画像をドラッグ&ドロップ、またはクリックして選択(複数可・1ファイル最大50MB)</div>
</div>
<ul class="previews"></ul>
<div><button type="submit">送信</button></div>
CSS
body{font-family:sans-serif;line-height:1.5;padding:20px;}
form{max-width:600px;margin:auto;}
h1{font-size:1.3rem;margin:0 0 12px;}
label{display:block;margin:8px 0;}
input[type="text"],input[type="email"],textarea{width:100%;padding:8px;border:1px solid #ccc;border-radius:4px;box-sizing: border-box;}
textarea{resize:vertical;}
.drop-zone{position:relative;border:2px dashed #ccc;padding:16px;text-align:center;cursor:pointer;margin:10px 0;}
.drop-zone.is-dragover{border-color:#333;background:#fafafa;}
.file-input{position:absolute;inset:0;opacity:0;cursor:pointer;}
.previews{list-style:none;margin:10px 0 0;padding:0;}
.preview{font-size:.9rem;margin-bottom:6px;}
button[type="submit"]{padding:8px 16px;border:1px solid #ccc;border-radius:4px;background:#f2f2f2;cursor:pointer;}
button[type="submit"]:hover{background:#e6e6e6;}
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 = 50 * 1024 * 1024;
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("50MB超過:", 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));