<div id="dataTableContainer"></div>
/* General styles */
body {
font-family: Arial, sans-serif;
}
.table-container {
border: 1px solid #e5e7eb;
border-bottom: none;
overflow: auto;
height: 400px;
}
.table {
border-collapse: separate;
border-spacing: 0;
width: 100%;
table-layout: fixed;
}
.table th,
.table td {
padding: 8px;
text-align: center;
border: 1px solid #e5e7eb;
}
.table td:nth-child(1),
table th:nth-child(1) {
background: red;
position: sticky;
left: 0;
z-index: 5;
color: white;
}
.table th:nth-child(1) {
z-index: 6;
}
.table th {
background-color: #1e3a8a;
color: white;
font-size: 14px;
font-weight: bold;
position: sticky;
top: 0;
z-index: 2;
}
.table td {
font-size: 14px;
color: #6b7280;
}
.table tr:nth-child(odd) {
background-color: #f9fafb;
}
.table tr:hover {
background-color: rgba(14, 116, 144, 0.1);
}
.no-data {
text-align: center;
font-size: 14px;
color: #9ca3af;
}
class DataTable {
constructor(containerId, columns, data, onRowClick) {
this.container = document.getElementById(containerId);
this.columns = columns;
this.data = data;
this.onRowClick = onRowClick;
this.render();
}
render() {
const tableContainer = document.createElement("div");
tableContainer.className = "table-container";
const table = document.createElement("table");
table.className = "table";
table.style.width = `max(100%, ${this.columns.reduce(
(acc, col) => acc + (col.width || 200),
0
)}px)`;
// Create table header
const thead = document.createElement("thead");
const headerRow = document.createElement("tr");
this.columns.forEach((col) => {
const th = document.createElement("th");
th.style.width = `${col.width || 200}px`;
th.textContent = col.label;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
// Create table body
const tbody = document.createElement("tbody");
if (this.data.length > 0) {
this.data.forEach((row, rowIndex) => {
const tr = document.createElement("tr");
tr.className = rowIndex % 2 === 0 ? "bg-white" : "bg-neutral-50";
tr.addEventListener("click", () => {
if (this.onRowClick) this.onRowClick(row);
});
this.columns.forEach((col) => {
const td = document.createElement("td");
const cellData =
row[col.key] !== null && row[col.key] !== undefined
? row[col.key]
: "-";
td.textContent = col.render
? col.render(cellData, row) || "-"
: cellData;
tr.appendChild(td);
});
tbody.appendChild(tr);
});
} else {
const noDataRow = document.createElement("tr");
const noDataCell = document.createElement("td");
noDataCell.colSpan = this.columns.length;
noDataCell.className = "no-data";
noDataCell.textContent = "No rows to display";
noDataRow.appendChild(noDataCell);
tbody.appendChild(noDataRow);
}
table.appendChild(tbody);
tableContainer.appendChild(table);
this.container.innerHTML = "";
this.container.appendChild(tableContainer);
}
}
// Usage example
const columns = [
{ label: "Name", key: "name", width: 150 },
{ label: "Age", key: "age", width: 100 },
{ label: "Email", key: "email", width: 200 },
{ label: "Email", key: "email", width: 200 },
{ label: "Email", key: "email", width: 200 }
];
const data = [
{ name: "John Doe", age: 25, email: "john.doe@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" },
{ name: "Jane Smith", age: 30, email: "jane.smith@example.com" }
];
const onRowClick = (row) => {
alert(`Row clicked: ${JSON.stringify(row)}`);
};
new DataTable("dataTableContainer", columns, data, onRowClick);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.