Source Code
<div class="container py-5 d-flex justify-content-center">
<div class="card bspaste-card">
<div class="card-body p-4">
<label class="form-label small fw-semibold">Attach a screenshot</label>
<div class="bspaste-zone" id="bspasteZone" tabindex="0">
<div id="bspasteEmpty">
<p class="mb-1">📋</p>
<p class="small mb-0">Click here, then press <kbd>Ctrl</kbd>+<kbd>V</kbd> to paste an image</p>
</div>
<div class="d-none" id="bspastePreviewWrap">
<img id="bspastePreview" alt="Pasted image preview">
<button type="button" class="btn btn-sm btn-outline-danger mt-2" id="bspasteRemove">Remove</button>
</div>
</div>
<p class="small text-muted mt-2 mb-0" id="bspasteStatus"> </p>
</div>
</div>
</div>.bspaste-card { width: 380px; max-width: 100%; border: 1px solid #eceef1; border-radius: 14px; }
.bspaste-zone {
border: 2px dashed #d1d5db; border-radius: 10px; padding: 24px;
text-align: center; color: #6b7280; cursor: text; transition: border-color .15s, background .15s;
}
.bspaste-zone:focus { outline: none; border-color: #6366f1; background: #f8f9ff; }
#bspastePreview { max-width: 100%; max-height: 160px; border-radius: 8px; display: block; margin: 0 auto; }const zone = document.getElementById('bspasteZone');
const empty = document.getElementById('bspasteEmpty');
const previewWrap = document.getElementById('bspastePreviewWrap');
const previewImg = document.getElementById('bspastePreview');
const status = document.getElementById('bspasteStatus');
let currentUrl = null;
function showImage(blob) {
if (currentUrl) URL.revokeObjectURL(currentUrl);
currentUrl = URL.createObjectURL(blob);
previewImg.src = currentUrl;
empty.classList.add('d-none');
previewWrap.classList.remove('d-none');
status.textContent = 'Image pasted (' + Math.round(blob.size / 1024) + ' KB).';
status.className = 'small text-success mt-2 mb-0';
}
zone.addEventListener('paste', e => {
const items = e.clipboardData ? e.clipboardData.items : [];
const imageItem = Array.from(items).find(item => item.type.startsWith('image/'));
if (!imageItem) {
status.textContent = 'No image found on the clipboard — copy an image first, then paste.';
status.className = 'small text-muted mt-2 mb-0';
return;
}
const blob = imageItem.getAsFile();
showImage(blob);
e.preventDefault();
});
document.getElementById('bspasteRemove').addEventListener('click', () => {
if (currentUrl) { URL.revokeObjectURL(currentUrl); currentUrl = null; }
previewImg.src = '';
previewWrap.classList.add('d-none');
empty.classList.remove('d-none');
status.textContent = '';
zone.focus();
});Bootstrap Paste-to-Upload (Clipboard Image Paste) — Free HTML CSS JS Snippet
Bootstrap Paste-to-Upload (Clipboard Image Paste) · Forms · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Bootstrap Paste-to-Upload (Clipboard Image Paste) — HTML, CSS & JavaScript

Pasting only works because the drop zone is a real, focusable element — tabindex="0" gives it something a drag-and-drop-only zone lacks: the ability to actually receive keyboard focus, which is a prerequisite for a paste event to ever fire on it at all. Clicking the zone focuses it, and only then does Ctrl+V/Cmd+V dispatch a genuine ClipboardEvent the listener can read from.
The listener reads e.clipboardData.items, finds the first item whose type starts with image/, and calls .getAsFile() to get a real Blob — this correctly ignores a clipboard holding plain copied text (which has no matching item) with an explicit, honest message rather than silently doing nothing or throwing an error.
showImage() revokes any previous object URL with URL.revokeObjectURL(currentUrl) before creating a new one, specifically so pasting a second image doesn't leak the first image's URL — the same object-URL cleanup discipline this collection's bootstrap-image-upload-preview applies per-thumbnail, applied here to a single always-current preview instead of a list.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Hand this snippet to an AI coding assistant like Claude and ask it to also accept a dragged-and-dropped image file on the same zone (combining paste and drag-and-drop into one input method), or to add a max-file-size check with a clear rejection message for an oversized pasted image.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a Bootstrap 5.3 paste-to-upload zone for clipboard images, using the real Bootstrap CDN framework (bootstrap.min.css and bootstrap.bundle.min.js), not custom CSS made to resemble it.
Requirements:
- A dashed-border zone with tabindex="0" so it can receive keyboard focus, showing instructions to click it and press Ctrl+V/Cmd+V.
- Listen for a real "paste" event on the zone, reading e.clipboardData.items to find the first item whose type starts with "image/", and get it as a real Blob via .getAsFile().
- On a successful image paste, show it as a preview using URL.createObjectURL, along with its file size in KB, and reveal a Remove button.
- If the pasted clipboard content contains no image (e.g. plain copied text), show a clear message explaining that instead of doing nothing.
- Revoke the previous object URL before creating a new one on a second paste, and also revoke it when Remove is clicked, so no object URL is ever left un-revoked.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Copy any imageTake a screenshot, or copy an image from another app or webpage, onto your system clipboard.
- 2Click the dashed paste zone on this pageIt visually focuses with a highlighted border, ready to receive a paste.
- 3Press Ctrl+V (or Cmd+V on Mac)The pasted image appears as a preview immediately, along with its size in KB.
- 4Try pasting plain copied text insteadA clear message explains no image was found, rather than doing nothing silently.
- 5Click "Remove"The preview clears, its object URL is released, and the zone returns to its empty, focused state ready for another paste.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Only a focused, focusable element receives a paste event through the standard clipboard shortcut — without tabindex, a plain div can never gain keyboard focus, so Ctrl+V would have nowhere to dispatch its ClipboardEvent to.
The items array is searched for an entry whose type starts with "image/"; when none is found, the zone shows an explicit "no image found" message instead of silently ignoring the paste or throwing an error.
Clipboard paste support for images varies significantly across mobile browsers and is generally less reliable than on desktop — a real implementation should keep a traditional file input available as a fallback on touch devices.
Yes. Attach the paste listener to a ref'd element in a mount hook, store the object URL in component state (revoking the previous one in the same setter, e.g. inside a state updater callback), and clean up on unmount to avoid a leaked URL if the component unmounts mid-preview.