Word to EPUB Converter — Free, Browser-Based | SmallStudyTools
100% Free · No Signup · Browser-Based
Upload a Word .docx manuscript and convert it into a valid EPUB e-book, right in your browser. Nothing is uploaded to a server. Pro Mode adds bulk conversion for multiple documents at once and optional chapter splitting by heading.
Add to Favorites
Share This Tool
● Pro Version is Free for now
Simple
Pro — Full Control
✓ Bulk convert multiple Word docs at once · ✓ Optional chapter splitting by Heading 1
📄 Upload Your Word Document
Drag & drop your Word document here
or click to browse — only .docx files are accepted
Browse Files
+ Add Another Word Document
📚 Convert to EPUB 📚 Split Into Chapters PRO
Splits the e-book into a separate chapter at every Heading 1, each with its own entry in the table of contents.
Off by default (single chapter)
\n`;
zip.file(`OEBPS/${fname}`, xhtml);
manifestItems.push(`
`);
spineItems.push(`
`);
navItems.push(`
${chTitle} `);
ncxItems.push(
`
${chTitle} `
);
});const navXhtml =
'\n' +
'\n\n' +
`
${bookTitle} \n\n\n
Contents \n` +
navItems.map(n => n + '\n').join('') +
' \n\n';
zip.file('OEBPS/nav.xhtml', navXhtml);const tocNcx =
'\n' +
'
\n' +
` \n` +
`${bookTitle} \n\n${ncxItems.join('\n')}\n \n `;
zip.file('OEBPS/toc.ncx', tocNcx);const contentOpf =
'\n' +
'
\n' +
`\n` +
`${uid} \n` +
`${bookTitle} \nen \n` +
` ${new Date().toISOString().replace(/\.\d+Z$/, 'Z')}\n` +
` \n\n` +
` \n` +
` \n` +
` \n` +
manifestItems.join('\n') +
`\n \n\n` + spineItems.join('\n') + `\n \n `;
zip.file('OEBPS/content.opf', contentOpf);return await zip.generateAsync({ type: 'blob', mimeType: 'application/epub+zip' });
}// ── CONVERSION ────────────────────────────────────────────────
async function startConversion() {
if (!queuedFiles.length || converting) return;
converting = true;
clearErr();
updateConvertBtn();
document.getElementById('progressWrap').classList.add('show');
fileResults = [];const totalFiles = queuedFiles.length;
const splitChapters = isPro && splitChaptersOn;try {
for (let fi = 0; fi < queuedFiles.length; fi++) {
const qf = queuedFiles[fi];
setProgress(`Reading "${qf.file.name}"...`, (fi + 0.3) / totalFiles);
const paragraphs = await extractDocxParagraphs(qf.file);
setProgress(`Building EPUB for "${qf.file.name}"...`, (fi + 0.8) / totalFiles);
const title = qf.file.name.replace(/\.docx$/i, '');
const epubBlob = await buildEpubBlob(paragraphs, title, splitChapters);
fileResults.push({ id: qf.id, name: qf.file.name, epubBlob, paraCount: paragraphs.length });
}
renderResults();
document.getElementById('resultsCard').classList.add('show');
document.getElementById('resultsCard').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
toast(`Converted ${fileResults.reduce((n, f) => n + f.paraCount, 0)} paragraph(s) to EPUB!`);
} catch (e) {
showErr('Something went wrong reading that Word document. Please make sure the file isn\'t corrupted or password-protected, and try again.');
} finally {
converting = false;
document.getElementById('progressWrap').classList.remove('show');
updateConvertBtn();
}
}function setProgress(label, frac) {
document.getElementById('progressLabel').textContent = label;
document.getElementById('progressFill').style.width = Math.min(100, Math.max(4, frac * 100)) + '%';
}// ── RESULTS / DOWNLOADS ───────────────────────────────────────
function renderResults() {
const wrap = document.getElementById('fileResultsList');
wrap.innerHTML = fileResults.map(fr => `
${escHtml(fr.name.replace(/\.docx$/i, ''))}.epub
${fr.paraCount} paragraph${fr.paraCount === 1 ? '' : 's'} · ${formatBytes(fr.epubBlob.size)}
Download
`).join('');const topActions = document.getElementById('resultsTopActions');
topActions.innerHTML = fileResults.length > 1
? `
Download Everything (.zip)
`
: '';
}function downloadEpub(fileId) {
const fr = fileResults.find(f => f.id === fileId);
if (!fr) return;
const base = fr.name.replace(/\.docx$/i, '');
triggerBlobDownload(fr.epubBlob, `${base}.epub`);
toast('EPUB file downloaded!');
}async function downloadEverythingZip() {
if (!fileResults.length) return;
const zip = new JSZip();
fileResults.forEach(fr => {
const base = fr.name.replace(/\.docx$/i, '');
zip.file(`${base}.epub`, fr.epubBlob);
});
const blob = await zip.generateAsync({ type: 'blob' });
triggerBlobDownload(blob, 'word-to-epub-converted.zip');
toast('ZIP downloaded!');
}function triggerBlobDownload(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url; a.download = filename; a.click();
setTimeout(() => URL.revokeObjectURL(url), 4000);
}function resetTool() {
queuedFiles = [];
fileResults = [];
renderFileChips();
updateConvertBtn();
document.getElementById('resultsCard').classList.remove('show');
document.getElementById('mainCol').scrollIntoView({ behavior: 'smooth', block: 'start' });
}// ── CHAPTER SPLITTING (pro) ────────────────────────────────────────
function toggleChapterSplit() {
if (!isPro) { toast('Chapter splitting is part of Pro Mode'); return; }
splitChaptersOn = !splitChaptersOn;
const sw = document.getElementById('chapterSplitSwitch');
if (sw) { sw.classList.toggle('on', splitChaptersOn); sw.setAttribute('aria-checked', String(splitChaptersOn)); }
}// ── MODE ──────────────────────────────────────────────────────
function setMode(mode) {
isPro = mode === 'pro';
document.getElementById('btnSimple').classList.toggle('active', !isPro);
document.getElementById('btnPro').classList.toggle('active', isPro);
document.body.classList.toggle('pro-mode', isPro);
const pb = document.getElementById('proBar'); if (pb) pb.style.display = isPro ? 'flex' : 'none';
document.getElementById('fileInput').multiple = isPro;
document.getElementById('uploadCardTitle').textContent = isPro ? 'Upload Your Word Documents' : 'Upload Your Word Document';
document.getElementById('dropzoneHint').textContent = isPro
? 'or click to browse — only .docx files are accepted, up to ' + MAX_FILES_PRO + ' at once'
: 'or click to browse — only .docx files are accepted';
if (!isPro && queuedFiles.length > 1) {
queuedFiles = queuedFiles.slice(0, 1);
renderFileChips();
toast('Switched to Simple Mode — only the first file was kept');
}
if (!isPro && splitChaptersOn) {
splitChaptersOn = false;
const sw = document.getElementById('chapterSplitSwitch');
if (sw) { sw.classList.remove('on'); sw.setAttribute('aria-checked', 'false'); }
}
updateConvertBtn();
}// ── UTILS ─────────────────────────────────────────────────────
function escHtml(s) { return String(s || '').replace(/&/g, '&').replace(//g, '>'); }
function toast(msg) { const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show'); setTimeout(() => t.classList.remove('show'), 2800); }
function formatBytes(bytes) {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(0) + ' KB';
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
}