Expandable Rows Table Template
Keep your tables clean and scannable by hiding secondary information in expandable rows.
With a single click, users can reveal a hidden row containing more details, perfect for order summaries, user profiles, or any data with primary and secondary importance.

About this Expandable Table
This "accordion" or "expandable row" pattern is a fantastic way to manage information density. The main table shows only the most critical data. A dedicated hidden row, placed directly after a main row in the HTML, contains additional details.
The JavaScript logic is simple:
- When a user clicks on a main row (specifically, one with the class
.row-expandable
), the script finds the very next row in the DOM. - It then toggles a "visible" class on that next row, which changes its
display
property. - A class is also toggled on the clicked row, which triggers a CSS transform on the
+
icon, rotating it 45 degrees to look like anx
(the close symbol). This could easily be modified to switch between+
and-
if you prefer.
The expandable row itself contains a td
with a colspan
attribute, allowing its content to span the full width of the table, perfect for displaying free-form details.
Features
- Keeps UI Clean: The primary table view remains uncluttered and easy to scan.
- On-Demand Detail: Provides rich information to the user without navigating to a new page.
- Smooth Transitions: Uses CSS transitions for a smooth opening and closing effect.
- Self-Contained: Built with simple, dependency-free JavaScript.
Ideal Use Cases
- E-commerce order history, where clicking an order reveals the specific products purchased.
- User lists, where clicking a user reveals their full profile or bio.
- Project management tables, where clicking a task reveals sub-tasks or comments.
Code
Here's the full code, including the HTML structure, CSS for the effect, and JavaScript to manage the state:
<style>
.expandable-table {
width: 100%;
border-collapse: collapse;
font-family: system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.expandable-table thead th {
padding: 12px;
background-color: #f2f2f2;
text-align: left;
font-weight: 600;
}
.expandable-table tbody td {
padding: 12px;
border-bottom: 1px solid #ddd;
}
/* This is the row the user clicks on */
.expandable-table .row-expandable {
cursor: pointer;
transition: background-color 0.2s;
}
.expandable-table .row-expandable:hover {
background-color: #f8f9fa;
}
/* This is the row that is hidden/shown */
.expandable-table .row-details {
display: none; /* Hidden by default */
}
.expandable-table .row-details.visible {
display: table-row; /* Show it when it has the 'visible' class */
}
.expandable-table .row-details td {
background-color: #f8f9fa;
padding: 20px;
border-bottom: 2px solid #ccc; /* A thicker border to separate it */
}
/* Styling for the expand/collapse icon */
.expandable-table .expand-icon {
font-weight: bold;
transition: transform 0.3s ease;
display: inline-block;
}
.expandable-table .row-expandable.open .expand-icon {
transform: rotate(45deg);
}
</style>
<table class="expandable-table" id="myExpandableTable">
<thead>
<tr>
<th scope="col" style="width: 5%;"></th>
<th scope="col">Order ID</th>
<th scope="col">Date</th>
<th scope="col">Total</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
<!-- First Record -->
<tr class="row-expandable">
<td><span class="expand-icon">+</span></td>
<td>#5501</td>
<td>2024-08-20</td>
<td>$199.50</td>
<td>Delivered</td>
</tr>
<tr class="row-details">
<td colspan="5">
<div>
<strong>Items Purchased:</strong>
<ul>
<li>Product A (1) - $99.50</li>
<li>Product B (2) - $100.00</li>
</ul>
<strong>Shipping Address:</strong> 123 Main St, Anytown, USA
</div>
</td>
</tr>
<!-- Second Record -->
<tr class="row-expandable">
<td><span class="expand-icon">+</span></td>
<td>#5502</td>
<td>2024-08-21</td>
<td>$45.00</td>
<td>Shipped</td>
</tr>
<tr class="row-details">
<td colspan="5">
<div>
<strong>Items Purchased:</strong>
<ul>
<li>Product C (1) - $45.00</li>
</ul>
<strong>Shipping Address:</strong> 456 Oak Ave, Somecity, USA
</div>
</td>
</tr>
<!-- Third Record -->
<tr class="row-expandable">
<td><span class="expand-icon">+</span></td>
<td>#5503</td>
<td>2024-08-22</td>
<td>$88.75</td>
<td>Processing</td>
</tr>
<tr class="row-details">
<td colspan="5">
<div>
<strong>Items Purchased:</strong>
<ul>
<li>Product D (3) - $75.00</li>
<li>Product E (1) - $13.75</li>
</ul>
<strong>Shipping Address:</strong> 789 Pine Ln, Otherville, USA
</div>
</td>
</tr>
</tbody>
</table>
<script>
/**
* Enables expandable/collapsible rows for a table.
* @param {string} tableId The ID of the table.
*/
function enableExpandableRows(tableId) {
const table = document.getElementById(tableId);
if (!table) return;
table.addEventListener('click', function(e) {
// Find the closest ancestor 'tr' that is expandable
const expandableRow = e.target.closest('tr.row-expandable');
if (!expandableRow) return;
// Find the very next TR element, which is the details row
const detailsRow = expandableRow.nextElementSibling;
if (detailsRow && detailsRow.classList.contains('row-details')) {
expandableRow.classList.toggle('open');
detailsRow.classList.toggle('visible');
}
});
}
// Initialize the functionality
enableExpandableRows('myExpandableTable');
</script>