Excel to HTML Converter — Free, Browser-Based | SmallStudyTools
100% Free · No Signup · Browser-Based

Excel to HTML Converter

Upload an .xlsx file and get a real, semantic HTML table, right in your browser — nothing is uploaded to a server. Pro Mode adds multi-sheet export, header row control, basic styling, zebra striping, captions, and numeric alignment.

● Pro Version is Free for now
✓ Bulk convert multiple files at once ·
✓ Multi-sheet export, header, styling & zebra ·
✓ Caption & right-aligned numeric columns
Day Night
📄 Upload Your Excel File
Drag & drop your .xlsx file here
or click to browse — only .xlsx files are accepted
Browse Files
🎉 Your HTML Table
📑 Sheet Handling PRO

Off = only the first sheet is converted. On = every sheet gets its own heading and table.

Combine all sheets
Off by default · on = one heading + table per sheet
🏷️ First Row as Header PRO

Turns the first row into real <th> header cells inside a <thead>.

Use first row as header
On by default · off = every row is a plain data row
🎨 Basic Styling PRO

Embeds a clean <style> block — borders, padding, header background.

Include basic styling
On by default · off = bare, unstyled table markup
🦓 Zebra Striping PRO

Shades alternating rows via CSS — needs Basic Styling turned on.

Alternate row shading
Off by default
🏷️ Table Caption PRO

Adds a real <caption> element above each table — the sheet name when combining sheets, or the file name otherwise.

Add caption with sheet/file name
Off by default
🔢 Right-Align Numbers PRO

Auto-detects columns that are entirely numeric and right-aligns just those <th>/<td> cells.

Right-align numeric columns
Off by default · detected automatically per column
`; }// ── CONVERSION ──────────────────────────────────────────────── async function startConversion() { if (!queuedFiles.length || converting) return; converting = true; clearErr(); updateConvertBtn(); document.getElementById('progressWrap').classList.add('show'); fileResults = [];const allSheets = isPro ? allSheetsOn : false; const hasHeader = isPro ? headerRowOn : true; const styled = isPro ? stylingOn : true; const zebra = isPro ? (zebraOn && stylingOn) : false; const showCaption = isPro ? captionOn : false; const rightAlign = isPro ? rightAlignNumeric : false; const totalFiles = queuedFiles.length;try { for (let fi = 0; fi < queuedFiles.length; fi++) { const qf = queuedFiles[fi]; setProgress(`Converting "${qf.file.name}"...`, (fi + 0.5) / totalFiles); await new Promise(r => setTimeout(r, 0)); const buf = await qf.file.arrayBuffer(); const wb = XLSX.read(buf, { type: 'array' }); const sheetNames = allSheets ? wb.SheetNames : [wb.SheetNames[0]]; const sheetsData = sheetNames.map(sn => ({ name: sn, rows: XLSX.utils.sheet_to_json(wb.Sheets[sn], { header: 1, raw: false, defval: '' }), })); const base = qf.file.name.replace(/\.xlsx$/i, ''); const fullHtml = buildFullHtmlForWorkbook(sheetsData, hasHeader, base, styled, zebra, allSheets, showCaption, rightAlign); let totalRows = 0, maxCols = 0; sheetsData.forEach(s => { totalRows += hasHeader ? Math.max(0, s.rows.length - 1) : s.rows.length; maxCols = Math.max(maxCols, s.rows.length ? s.rows[0].length : 0); }); fileResults.push({ id: qf.id, name: base, text: fullHtml, rowCount: totalRows, colCount: maxCols, sheetCount: sheetsData.length }); } renderResults(); document.getElementById('resultsCard').classList.add('show'); document.getElementById('resultsCard').scrollIntoView({ behavior: 'smooth', block: 'nearest' }); toast(`Converted ${fileResults.length} file${fileResults.length === 1 ? '' : 's'} to HTML!`); } catch (e) { showErr('Something went wrong converting that file. Please make sure it isn\'t corrupted, 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)}.html
${fr.sheetCount} sheet${fr.sheetCount === 1 ? '' : 's'} · ${fr.rowCount} row${fr.rowCount === 1 ? '' : 's'} · ${fr.colCount} column${fr.colCount === 1 ? '' : 's'} · ${formatBytes(fr.text.length)}
${escHtml(fr.text.slice(0, 700))}${fr.text.length > 700 ? '\n…' : ''}
`).join('');const topActions = document.getElementById('resultsTopActions'); topActions.innerHTML = fileResults.length > 1 ? `` : ''; }function copyResult(fileId) { const fr = fileResults.find(f => f.id === fileId); if (!fr) return; navigator.clipboard.writeText(fr.text) .then(() => toast('Copied to clipboard!')) .catch(() => toast('Could not copy — try the Download button instead')); }function downloadResult(fileId) { const fr = fileResults.find(f => f.id === fileId); if (!fr) return; const blob = new Blob([fr.text], { type: 'text/html' }); triggerBlobDownload(blob, `${fr.name}.html`); toast('HTML file downloaded!'); }async function downloadEverythingZip() { if (!fileResults.length) return; const zip = new JSZip(); fileResults.forEach(fr => { zip.file(`${fr.name}.html`, fr.text); }); const blob = await zip.generateAsync({ type: 'blob' }); triggerBlobDownload(blob, 'excel-to-html-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' }); }// ── SHEET HANDLING / HEADER / STYLING / ZEBRA (pro) ───────────── function toggleAllSheets() { if (!isPro) { toast('Multi-sheet export is part of Pro Mode'); return; } allSheetsOn = !allSheetsOn; document.getElementById('allSheetsSwitch').classList.toggle('on', allSheetsOn); document.getElementById('allSheetsSwitch').setAttribute('aria-checked', String(allSheetsOn)); } function toggleHeaderRow() { if (!isPro) { toast('Header row control is part of Pro Mode'); return; } headerRowOn = !headerRowOn; document.getElementById('headerSwitch').classList.toggle('on', headerRowOn); document.getElementById('headerSwitch').setAttribute('aria-checked', String(headerRowOn)); } function toggleStyling() { if (!isPro) { toast('Styling control is part of Pro Mode'); return; } stylingOn = !stylingOn; document.getElementById('stylingSwitch').classList.toggle('on', stylingOn); document.getElementById('stylingSwitch').setAttribute('aria-checked', String(stylingOn)); updateZebraAvailability(); } function toggleZebra() { if (!isPro) { toast('Zebra striping is part of Pro Mode'); return; } if (!stylingOn) { toast('Turn on Basic Styling first — zebra striping is a CSS rule'); return; } zebraOn = !zebraOn; document.getElementById('zebraSwitch').classList.toggle('on', zebraOn); document.getElementById('zebraSwitch').setAttribute('aria-checked', String(zebraOn)); } function toggleCaption() { if (!isPro) { toast('Table caption is part of Pro Mode'); return; } captionOn = !captionOn; document.getElementById('captionSwitch').classList.toggle('on', captionOn); document.getElementById('captionSwitch').setAttribute('aria-checked', String(captionOn)); } function toggleRightAlign() { if (!isPro) { toast('Right-align numeric columns is part of Pro Mode'); return; } rightAlignNumeric = !rightAlignNumeric; document.getElementById('rightAlignSwitch').classList.toggle('on', rightAlignNumeric); document.getElementById('rightAlignSwitch').setAttribute('aria-checked', String(rightAlignNumeric)); } function updateZebraAvailability() { const sw = document.getElementById('zebraSwitch'); const sub = document.getElementById('zebraSub'); if (!sw) return; sw.disabled = !stylingOn; if (sub) sub.textContent = stylingOn ? 'Off by default' : 'Off by default · requires styling to be on'; }// ── 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 Excel Files' : 'Upload Your Excel File'; document.getElementById('dropzoneHint').textContent = isPro ? 'or click to browse — only .xlsx files are accepted, up to ' + MAX_FILES_PRO + ' at once' : 'or click to browse — only .xlsx 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) { allSheetsOn = false; document.getElementById('allSheetsSwitch').classList.remove('on'); document.getElementById('allSheetsSwitch').setAttribute('aria-checked', 'false'); headerRowOn = true; document.getElementById('headerSwitch').classList.add('on'); document.getElementById('headerSwitch').setAttribute('aria-checked', 'true'); stylingOn = true; document.getElementById('stylingSwitch').classList.add('on'); document.getElementById('stylingSwitch').setAttribute('aria-checked', 'true'); zebraOn = false; document.getElementById('zebraSwitch').classList.remove('on'); document.getElementById('zebraSwitch').setAttribute('aria-checked', 'false'); updateZebraAvailability(); captionOn = false; document.getElementById('captionSwitch').classList.remove('on'); document.getElementById('captionSwitch').setAttribute('aria-checked', 'false'); rightAlignNumeric = false; document.getElementById('rightAlignSwitch').classList.remove('on'); document.getElementById('rightAlignSwitch').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'; }

How to Use the Excel to HTML Converter

From an .xlsx upload to a real, semantic HTML table in seconds. No signup, and your spreadsheet never leaves your browser.

1
Upload Your Excel File
Drag and drop your .xlsx file, or click to browse. Files stay under 30MB and are verified by their real content — zip magic bytes plus an actual SheetJS parse, not just the file extension.
2
Real HTML Table Builds Instantly
Your rows and columns become genuine <table>, <thead>, and <tbody> markup right in the browser — not a screenshot or an image — with every cell value HTML-escaped as it's inserted.
3
Switch to Pro Mode
Unlock multi-sheet export, first-row header control, basic styling, zebra striping, a real <caption> element, and automatic right-aligned numeric columns — plus bulk conversion for up to 20 files at once.
4
Check Sheets, Rows & Columns
Each result shows the sheet count, row count, column count, and file size, so you can confirm the markup matches your source workbook before downloading.
5
Download .html, or Zip
Copy the markup to your clipboard, download a single .html file, or grab every converted file at once in a .zip when converting a batch in Pro Mode.

Everything above runs entirely in your browser. Your Excel file is never uploaded to a server, so its contents stay completely private from start to finish.

Specifications
Price Free
Signup Not Required
Data Processing Local only, in your browser
Output Format Real HTML table markup (.html)
File Size Limit 30MB per .xlsx · up to 20 files in Pro
Source Format .xlsx (Excel 2007+)
Pro Mode Options Sheet Handling, First Row as Header, Basic Styling, Zebra Striping, Table Caption, Right-Align Numbers
Found a bug or something not working right? Let us know and we'll fix it, every report helps make this tool better.
Report an Issue

Excel to HTML Table Converter: Turn a Real Workbook Into Real, Semantic Markup

Quick answer: Upload your .xlsx file above and this tool builds a real <table> with proper <thead> and <tbody> markup, free and entirely in your browser. Pro Mode adds multi-sheet export, a real <caption> element, and automatically right-aligned numeric columns, plus first-row header control, basic styling, and zebra striping.

An Excel workbook is not a web page — it's a proprietary, zip-based file format with sheets, cell formulas, number formats, and styling that a browser has no native way to render. An HTML table is what a browser actually renders: proper markup that a screen reader can navigate, a search engine can index, and your own CSS can style. Converting a workbook into that markup is the step between a spreadsheet export and something you can genuinely embed in a web page, blog post, internal wiki, or documentation site.

Every converter on SmallStudyTools is tested with real files before it ships. This tool checks that an uploaded file is genuinely an .xlsx workbook — not just named that way — by reading its actual bytes: the first two bytes must be the zip file's own magic number, and the file then has to actually parse as a valid workbook through SheetJS. A renamed text file or a corrupted download is rejected with a clear message instead of silently producing a broken table.

1How This Excel to HTML Converter Works

The tool reads your workbook entirely client-side with the SheetJS library, then builds genuine table markup directly from the parsed rows and columns: a <thead> with <th> cells from the first row (when header detection is enabled), and a <tbody> with a <tr> and a set of <td> cells for every remaining row. Every value is HTML-escaped as it's inserted, so ampersands, angle brackets, and any accidental markup sitting in a cell render as plain text rather than being interpreted as HTML. The result is real, standards-compliant markup — not an image, a canvas rendering, or a copy-pasted screenshot dressed up as a table.

2Simple vs Pro Mode

FeatureSimplePro
Convert one Excel workbook into a real HTML table✓✓
HTML-escaped, XSS-safe cell values✓✓
Copy, preview, or download the result✓✓
Sheet Handling — every sheet gets its own heading + table—✓
First Row as Header — real <thead>/<th>—✓
Basic Styling — embedded <style> block—✓
Zebra Striping on alternating rows—✓
Table Caption — a real <caption> with the sheet/file name—✓
Right-Align Numbers, auto-detected per column—✓
Convert up to 20 .xlsx files at once, download as ZIP—✓

Simple Mode covers the everyday case: upload one .xlsx and get back a complete, styled HTML document with a real table inside it, first sheet only, header row and all. Pro Mode, currently free to use, hands over structure and layout control — every sheet in the workbook, a caption, numeric alignment — plus bulk conversion for anyone turning a whole folder of exports into tables at once.

3Multi-Sheet Export, Captions, and Right-Aligned Numbers

Three Pro options exist specifically because a real workbook, unlike a single CSV, can hold more than one sheet and more than one kind of column. Sheet Handling switches the output from "first sheet only" to every sheet in the workbook, each one getting its own <h2> heading (the sheet's own name) followed by its own independent <table> — so a workbook with a "Sales" tab and an "Inventory" tab produces two clearly labeled tables in one document, not just the first one silently dropped. Table Caption adds a real <caption> element directly inside each <table>, genuinely tied to that table's own sheet name when Sheet Handling is combining every sheet, or to the source file's name when only one table is produced — giving assistive technology and readers a proper, table-specific description rather than a generic label. Right-Align Numbers scans every column independently — per sheet, so a numeric column in "Inventory" doesn't get confused with a text column in "Sales" — and right-aligns only the columns where every non-empty value is genuinely numeric, leaving columns that mix text and numbers, like a notes field, exactly as they are.

4Common Reasons People Convert Excel to HTML

📝
Embedding a Spreadsheet Export in a Blog Post
📚
Publishing a Reference Table in Documentation
🌐
Adding a Data Table to a Static Website
♿
Making Workbook Data Screen-Reader Accessible
🔍
Publishing Data That's Actually Indexable by Search Engines
🧩
Pasting a Table Into a CMS or Email Builder

A workbook can't be embedded in a web page as-is — Excel's own .xlsx format needs proprietary software or a library just to open it, let alone render it in a browser. A real <table> is also fundamentally different from a screenshot of a spreadsheet: it's selectable and copyable text, it's readable by screen readers and other assistive technology, and search engines can index its content the way they can't with a pasted image or an embedded spreadsheet viewer. Whether the destination is a blog post, a documentation site, an internal wiki, or a CMS's raw-HTML block, converting once gets a workbook export into a format the web actually understands.

5Multiple Sheets, Formulas, and Why the Output Stays Clean

Excel workbooks routinely carry things a plain HTML table has no way to represent: multiple sheets, live formulas, number formats, and cell styling that only makes sense inside a spreadsheet application. This tool reads each sheet's cells through SheetJS's calculated, display-ready values — so a cell holding a formula like =SUM(B2:B10) contributes its resulting number to the table, not the formula text itself, exactly as you'd see it looking at the sheet in Excel. Sheet Handling turns the multi-sheet structure into a genuine advantage rather than a limitation: instead of forcing you to export and convert each tab separately, one upload converts the whole workbook, sheet order preserved, each one clearly headed and captioned in the resulting HTML document.

6Why HTML-Escaping Matters for Real-World Spreadsheets

Spreadsheets pulled from CRM exports, survey tools, or forms people filled in by hand can easily contain characters that look like HTML — an ampersand in a company name, angle brackets typed by accident, or in rarer cases something that looks like an actual script tag. If those characters were inserted into the page raw, a browser would try to interpret them as markup instead of displaying them as text, which can break the table's layout or, in a worst case, execute unintended script content. Every cell value passed through this tool is HTML-escaped before it's placed into the generated <table>, so those characters always render as the literal text they are, never as live markup — the same protection you'd want from any tool that turns arbitrary spreadsheet data into HTML.

Privacy Note

Every Excel file you convert here is processed entirely inside your own browser tab using JavaScript running on your device. Nothing is uploaded, stored, or transmitted to a server at any point, whether you're in Simple Mode or Pro Mode — including every sheet in a multi-sheet workbook.

7Frequently Asked Questions

Is there a free way to convert an Excel file to an HTML table?
Yes. Upload your .xlsx file above and it becomes a real, semantic HTML table right in your browser within a couple of seconds. There's no account to create and no limit on how many times you can use it, since the whole conversion happens on your own device.
Does this produce a real <table>, or an image that looks like one?
A real <table>. The output is genuine markup — <table>, <thead>, <tbody>, <tr>, <th>, and <td> elements built directly from your workbook's rows and columns — not a screenshot or a rendered image. That means it's selectable, accessible to screen readers, indexable by search engines, and stylable with your own CSS.
Can I convert every sheet in my workbook, not just the first one?
Yes, in Pro Mode. Turn on Sheet Handling and every sheet in the workbook gets its own heading and its own table in the output, in the same order they appear in Excel, instead of only the first sheet being converted.
Can I add a caption or right-align number columns?
Yes, both in Pro Mode. Table Caption adds a real <caption> element above each table using the sheet name (or the file name when only one sheet is converted). Right-Align Numbers automatically detects which columns contain only numeric values and right-aligns just those cells, leaving text columns untouched — no manual column-by-column styling required.
Is the generated HTML safe from XSS if my spreadsheet contains HTML-looking text?
Yes. Every cell value is HTML-escaped before it's inserted into the table, so a cell containing something like <script> or an ampersand is converted to its safe entity form and rendered as plain text, never executed as markup. This matters if your workbook includes freeform user input, since raw HTML in a cell can't break out of the table or inject a script tag.
Can I convert multiple Excel files to HTML tables at once?
Yes, in Pro Mode. Queue up to 20 .xlsx files, apply the same sheet handling, header, styling, caption, and alignment settings to all of them, convert the whole batch in one pass, and download every resulting HTML file together as a single ZIP.

Built on open standards. The output follows the WHATWG HTML Living Standard's tables specification, section 4.9, "Tabular data" — the same living document that defines <table>, <thead>, <tbody>, <caption>, and every other table element this tool generates.

Lilly
Here to help you find a tool
Search tools Search blogs
Try me to find a tool! 👋