Bootstrap Duplicate File Detection on Upload — Free HTML CSS JS Snippet
Bootstrap Duplicate File Detection on Upload · Forms · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<div class="container py-5 d-flex justify-content-center">
<div class="card bsdupe-card">
<div class="card-body p-4">
<label class="form-label small fw-semibold">Attach files</label>
<input type="file" class="form-control mb-2" id="bsdupeInput" multiple>
<p class="small mb-3 d-none" id="bsdupeWarning"></p>
<ul class="list-unstyled mb-0" id="bsdupeList"></ul>
</div>
</div>
</div>.bsdupe-card { width: 400px; max-width: 100%; border: 1px solid #eceef1; border-radius: 14px; }
#bsdupeWarning { color: #b45309; background: #fffbeb; padding: 8px 10px; border-radius: 8px; }
.bsdupe-item { display: flex; justify-content: space-between; padding: 7px 0; font-size: 13.5px; border-bottom: 1px solid #f1f2f5; }
.bsdupe-item:last-child { border-bottom: none; }const input = document.getElementById('bsdupeInput');
const warning = document.getElementById('bsdupeWarning');
const list = document.getElementById('bsdupeList');
let added = [];
// A cheap but effective duplicate signature: real content hashing would need
// to read every file's bytes, which is overkill here — name + size + last
// modified time together are extremely unlikely to collide for two genuinely
// different files someone is attaching to the same form.
function signature(file) {
return file.name + '::' + file.size + '::' + file.lastModified;
}
function render() {
list.innerHTML = added.map(f =>
'<li class="bsdupe-item"><span>' + f.name + '</span><span class="text-muted">' + Math.round(f.size / 1024) + ' KB</span></li>'
).join('') || '<li class="bsdupe-item text-muted">No files attached yet.</li>';
}
input.addEventListener('change', () => {
const incoming = Array.from(input.files);
const existingSignatures = new Set(added.map(signature));
const duplicates = [];
incoming.forEach(file => {
const sig = signature(file);
if (existingSignatures.has(sig)) {
duplicates.push(file.name);
} else {
existingSignatures.add(sig);
added.push(file);
}
});
if (duplicates.length) {
warning.textContent = (duplicates.length === 1 ? 'Skipped duplicate: ' : 'Skipped duplicates: ') + duplicates.join(', ');
warning.classList.remove('d-none');
} else {
warning.classList.add('d-none');
}
render();
input.value = '';
});
render();Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Bootstrap Duplicate File Detection on Upload — HTML, CSS & JavaScript

Detecting a true duplicate needs a signature that's cheap to compute but specific enough to trust — signature() combines a file's name, size, and lastModified timestamp into one string, since two genuinely different files sharing all three values at once is vanishingly unlikely, while hashing every byte of every file just to compare them would be needless work for a client-side check like this one.
Every incoming file is checked against a Set built from every file already added, and — this is the detail that's easy to get wrong — newly accepted files are added to that same existingSignatures Set as they're processed, not only checked against the pre-existing list. Without that, selecting the identical file twice within a single multi-select dialog (dragging the same file into the selection twice, which some file pickers allow) would let both copies through, since neither would exist in the list yet at comparison time.
The warning message is built from an actual list of the skipped file names, not a generic "duplicate detected" — duplicates.push(file.name) collects every skipped file across the current selection so a user attaching ten files at once, three of which were already added, sees exactly which three were rejected rather than being left to guess.
Step by step
How to Use
- 1Select a fileIt's added to the list below with its size shown.
- 2Open the file picker again and select the exact same fileA warning appears reading "Skipped duplicate: [filename]" — it isn't added a second time.
- 3Select a mix of new and already-added files at onceThe new ones are added normally, and the warning lists only the ones that were actually duplicates.
- 4Select only genuinely new filesNo warning appears at all — the message only shows when a real duplicate was caught.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
No — it compares name, size, and last-modified timestamp together, which correctly catches the overwhelmingly common real case (re-selecting the same file) without the cost of reading and hashing every byte of every file client-side.
It's theoretically possible for two unrelated files to share an identical name, byte size, and modification timestamp down to the millisecond, but in practice this is extremely unlikely for files someone is deliberately attaching to the same form.
It's still caught — each file in the current selection is added to the comparison Set as it's processed, so the second occurrence in the same batch is checked against the first one already added moments earlier.
Yes. Keep the added files array in component state, and run the same signature-based Set comparison inside your change handler before merging new files into that state — no other logic needs to change.