JSFiddle - React, Tailwind, and code Playground

by Scott Kaye

HTML

<table downloadable="Test" border="1">
	<tr>
		<th colspan="2">Header 1</th>
		<th>Header 3</th>
	</tr>
	<tr>
		<td>&nbsp;</td>
		<td>Emptiness, "inside"</td>
		<td>Test</td>
	</tr>
	<tr>
		<td csv-numeric></td>
		<td csv-numeric></td>
		<td csv-numeric></td>
	</tr>
</table>

JavaScript

console.clear();
(function DownloadableTables() {
	// Add download button before each table
	let tables = document.querySelectorAll("table[downloadable]");
	tables.forEach(table => {
		let csv = "";
		
		// Loop through each row
		table.querySelectorAll("tr").forEach(tr => {
			// Get cells
			tr.querySelectorAll("td,th").forEach(cell => {
				let content = `"${cell.innerText.trim().replace(/"/g, '\\"')}"`;
				let defaultValue = "";
				
				if (cell.hasAttribute("csv-numeric")) {
					content = content.replace(/[^0-9.]/g, "");
					defaultValue = 0;
				}
				
				// Resolve "width" with extra cells
				csv += `${content}${`${defaultValue},`.repeat(cell.colSpan)}`;
			});
			csv += "\r\n";
		});
		
		console.log(csv);
		
		let link = document.createElement("a");
		link.download = (table.getAttribute("downloadable") || "Untitled") + ".csv";
		link.className = "download-link";
		link.href = `data:text/csv;charset=UTF-8,${encodeURIComponent(csv)}`;
		link.textContent = "[download]";
		table.parentNode.insertBefore(link, table);
	});
}());