Skip to content

Tailwind CSS - Tables

Styling tables effectively is essential for presenting tabular data clearly. Tailwind CSS provides a suite of utilities to control table layout, borders, spacing, and more, enabling you to build modern, responsive, and accessible data tables.

Below are the key utilities for styling tables. They are often used in combination to achieve the desired look and behavior.

Utility GroupDescription
Border CollapseUse border-collapse (modern, shared borders) or border-separate (borders have space between them).
Border SpacingUse border-spacing-x-{amount} and border-spacing-y-{amount} to control space between cells. Only works with border-separate.
Table LayoutUse table-auto (columns adapt to content) or table-fixed (columns have fixed, equal widths). table-fixed is often better for performance and predictable layouts.
Caption SideUse caption-top or caption-bottom to control the placement of the <caption> element, which is important for accessibility.

Mini-Project: Building a Modern, Responsive Data Table

Section titled “Mini-Project: Building a Modern, Responsive Data Table”

Let’s build a user data table from scratch, applying modern styling and making it responsive for mobile devices.

We’ll start with a table-fixed layout, full width, and clean row dividers.

<div class="overflow-x-auto rounded-lg shadow-md">
<table class="w-full table-fixed text-sm text-left text-slate-500">
<caption class="p-5 text-lg font-semibold text-left text-slate-900 bg-white">
Our Users
<p class="mt-1 text-sm font-normal text-slate-500">Browse a list of users in our system.</p>
</caption>
<thead class="text-xs text-slate-700 uppercase bg-slate-100">
<tr>
<th scope="col" class="px-6 py-3 w-1/3">Name</th>
<th scope="col" class="px-6 py-3 w-1/3">Role</th>
<th scope="col" class="px-6 py-3 w-1/3">Status</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200">
<tr class="bg-white hover:bg-slate-50">
<td class="px-6 py-4 font-medium text-slate-900">Jane Doe</td>
<td class="px-6 py-4">Administrator</td>
<td class="px-6 py-4 text-green-600">Active</td>
</tr>
<tr class="bg-white hover:bg-slate-50">
<td class="px-6 py-4 font-medium text-slate-900">John Smith</td>
<td class="px-6 py-4">Developer</td>
<td class="px-6 py-4 text-green-600">Active</td>
</tr>
<tr class="bg-white hover:bg-slate-50">
<td class="px-6 py-4 font-medium text-slate-900">Alex Ray</td>
<td class="px-6 py-4">Designer</td>
<td class="px-6 py-4 text-red-600">Inactive</td>
</tr>
</tbody>
</table>
</div>

Zebra-striping (alternating row colors) improves readability. Tailwind makes this easy with the odd: and even: variants.

<!-- In your tbody... -->
<tbody class="divide-y divide-slate-200">
<!-- Simply add odd/even background color classes to the <tr> element -->
<tr class="odd:bg-white even:bg-slate-50 hover:bg-blue-100">
<!-- ... -->
</tr>
<tr class="odd:bg-white even:bg-slate-50 hover:bg-blue-100">
<!-- ... -->
</tr>
</tbody>

Traditional tables are notoriously difficult on small screens. A common modern pattern is to transform the table into a card-like layout on mobile. We can achieve this with responsive utilities.

The strategy is to hide the <thead> on mobile and change the display of <td> elements to block, using pseudo-elements to add labels. This requires a bit of custom CSS, which you can add to your main stylesheet.

/* Add this to your main CSS file (e.g., style.css) */
@media (max-width: 768px) {
.responsive-table thead {
display: none;
}
.responsive-table tr {
display: block;
margin-bottom: 1rem;
border-bottom: 2px solid #ddd;
}
.responsive-table td {
display: block;
text-align: right;
border-bottom: 1px dotted #ccc;
}
.responsive-table td::before {
content: attr(data-label);
float: left;
font-weight: bold;
text-transform: uppercase;
}
}

Add the responsive-table class to your table and data-label attributes to your <td> elements.

<table class="w-full text-sm responsive-table">
<!-- ... thead ... -->
<tbody>
<tr>
<td data-label="Name" class="px-6 py-4 font-medium text-slate-900">Jane Doe</td>
<td data-label="Role" class="px-6 py-4">Administrator</td>
<td data-label="Status" class="px-6 py-4 text-green-600">Active</td>
</tr>
<!-- ... more rows ... -->
</tbody>
</table>
  • Always use <caption>: It provides a programmatic title for the table.
  • Use <thead> and <th>: Properly identify table headers.
  • Add scope="col" or scope="row" to <th> elements: This explicitly tells screen readers whether the header applies to a column or a row, which is critical for understanding data relationships.