Bulma Table
Bulma provides beautifully styled tables with minimal CSS. The table component includes modifiers for different styles, responsive containers, and easy customization.
Basic Table
Simple table with default styling:
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>John Doe</td>
<td>john@example.com</td>
<td>Admin</td>
</tr>
<tr>
<td>2</td>
<td>Jane Smith</td>
<td>jane@example.com</td>
<td>User</td>
</tr>
</tbody>
</table>| ID | Name | Role | |
|---|---|---|---|
| 1 | John Doe | john@example.com | Admin |
| 2 | Jane Smith | jane@example.com | User |
Table Modifiers
Apply different styles to tables:
<!-- Bordered table --> <table class="table is-bordered"> <!-- Striped table --> <table class="table is-striped"> <!-- Narrow table --> <table class="table is-narrow"> <!-- Hoverable rows --> <table class="table is-hoverable"> <!-- Full width table --> <table class="table is-fullwidth"> <!-- Combine modifiers --> <table class="table is-striped is-hoverable is-fullwidth">
| Modifier | Description |
|---|---|
is-bordered | Adds borders to all cells |
is-striped | Adds zebra striping |
is-narrow | Makes cells more compact |
is-hoverable | Highlights row on hover |
is-fullwidth | Table takes full container width |
Table with Container
Use table-container for responsive scrolling:
<div class="table-container">
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<!-- Table content -->
</table>
</div>Table Header Colors
<!-- Dark header -->
<thead>
<tr class="has-background-dark has-text-white">
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<!-- Primary header -->
<thead>
<tr class="has-background-primary has-text-white">
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<!-- Gradient header -->
<thead>
<tr style="background: linear-gradient(to right, #667eea, #764ba2); color: white;">
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>Table Cell Alignment
<table class="table">
<thead>
<tr>
<th class="has-text-left">Left Aligned</th>
<th class="has-text-centered">Centered</th>
<th class="has-text-right">Right Aligned</th>
</tr>
</thead>
<tbody>
<tr>
<td class="has-text-left">Left</td>
<td class="has-text-centered">Center</td>
<td class="has-text-right">Right</td>
</tr>
</tbody>
</table>Table with Icons and Badges
<table class="table">
<thead>
<tr>
<th>Status</th>
<th>Task</th>
<th>Priority</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="icon has-text-success">
<i class="fas fa-check-circle"></i>
</span>
<span>Completed</span>
</td>
<td>Design homepage</td>
<td>
<span class="tag is-primary">High</span>
</td>
<td>
<button class="button is-small is-info">
<span class="icon"><i class="fas fa-edit"></i></span>
</button>
</td>
</tr>
<tr>
<td>
<span class="icon has-text-warning">
<i class="fas fa-exclamation-circle"></i>
</span>
<span>Pending</span>
</td>
<td>Write documentation</td>
<td>
<span class="tag is-warning">Medium</span>
</td>
<td>
<button class="button is-small is-success">
<span class="icon"><i class="fas fa-check"></i></span>
</button>
</td>
</tr>
</tbody>
</table>Sortable Table Headers
<table class="table is-hoverable">
<thead>
<tr>
<th>
<a href="#" class="is-flex is-align-items-center">
Name
<span class="icon ml-1">
<i class="fas fa-sort"></i>
</span>
</a>
</th>
<th>
<a href="#" class="is-flex is-align-items-center">
Date
<span class="icon ml-1">
<i class="fas fa-sort"></i>
</span>
</a>
</th>
<th>
<a href="#" class="is-flex is-align-items-center">
Amount
<span class="icon ml-1">
<i class="fas fa-sort"></i>
</span>
</a>
</th>
</tr>
</thead>
<tbody>
<!-- Table data -->
</tbody>
</table>
<script>
// Simple sorting functionality
document.querySelectorAll('th a').forEach(header => {
header.addEventListener('click', function(e) {
e.preventDefault();
const table = this.closest('table');
const headerIndex = Array.from(this.parentNode.parentNode.children).indexOf(this.parentNode);
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
rows.sort((a, b) => {
const aText = a.children[headerIndex].textContent.trim();
const bText = b.children[headerIndex].textContent.trim();
// Try to parse as number first
const aNum = parseFloat(aText.replace(/[^0-9.-]+/g, ''));
const bNum = parseFloat(bText.replace(/[^0-9.-]+/g, ''));
if (!isNaN(aNum) && !isNaN(bNum)) {
return aNum - bNum;
}
// Otherwise sort as string
return aText.localeCompare(bText);
});
// Clear and re-append sorted rows
tbody.innerHTML = '';
rows.forEach(row => tbody.appendChild(row));
});
});
</script>Responsive Tables
Make tables scrollable on mobile:
<div class="table-container is-scrollable">
<table class="table is-bordered is-striped">
<!-- Wide table that will scroll on mobile -->
</table>
</div>
<style>
.is-scrollable {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
/* Alternatively, use Bulma's responsive table */
@media screen and (max-width: 768px) {
.table.is-responsive {
display: block;
overflow-x: auto;
white-space: nowrap;
}
}
</style>JavaScript Integration
Add interactivity to tables:
// Row selection
document.querySelectorAll('.table tbody tr').forEach(row => {
row.addEventListener('click', function() {
this.classList.toggle('has-background-light');
});
});
// Filter table rows
function filterTable(inputId, tableId) {
const filter = document.getElementById(inputId).value.toLowerCase();
const table = document.getElementById(tableId);
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
const text = row.textContent.toLowerCase();
if (text.includes(filter)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
}
// Paginate table
function paginateTable(tableId, pageSize) {
const table = document.getElementById(tableId);
const rows = table.querySelectorAll('tbody tr');
const totalPages = Math.ceil(rows.length / pageSize);
function showPage(page) {
const start = (page - 1) * pageSize;
const end = start + pageSize;
rows.forEach((row, index) => {
if (index >= start && index < end) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
}
return { showPage, totalPages };
}
// Initialize pagination
const tablePaginator = paginateTable('my-table', 10);
tablePaginator.showPage(1);Practical Examples
User Management Table
<div class="box">
<div class="level">
<div class="level-left">
<div class="level-item">
<h2 class="title is-4">Users</h2>
</div>
<div class="level-item">
<div class="field has-addons">
<div class="control">
<input class="input" type="text" placeholder="Search users..." id="user-search">
</div>
<div class="control">
<button class="button is-primary">
<span class="icon"><i class="fas fa-search"></i></span>
</button>
</div>
</div>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button class="button is-success">
<span class="icon"><i class="fas fa-plus"></i></span>
<span>Add User</span>
</button>
</div>
</div>
</div>
<div class="table-container">
<table class="table is-fullwidth is-striped is-hoverable" id="users-table">
<thead>
<tr class="has-background-light">
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Role</th>
<th>Status</th>
<th>Joined</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>
<div class="media">
<div class="media-left">
<figure class="image is-32x32">
<img class="is-rounded" src="avatar1.jpg" alt="Avatar">
</figure>
</div>
<div class="media-content">
<p class="has-text-weight-semibold">John Doe</p>
</div>
</div>
</td>
<td>john@example.com</td>
<td>
<span class="tag is-primary">Admin</span>
</td>
<td>
<span class="tag is-success">Active</span>
</td>
<td>2024-01-15</td>
<td>
<div class="buttons are-small">
<button class="button is-info">
<span class="icon"><i class="fas fa-edit"></i></span>
</button>
<button class="button is-danger">
<span class="icon"><i class="fas fa-trash"></i></span>
</button>
</div>
</td>
</tr>
<!-- More rows -->
</tbody>
</table>
</div>
<!-- Pagination -->
<nav class="pagination is-centered mt-4">
<!-- Pagination controls -->
</nav>
</div>Product Inventory Table
<div class="card">
<div class="card-content">
<h3 class="title is-4">Inventory</h3>
<table class="table is-fullwidth is-striped">
<thead>
<tr>
<th>Product</th>
<th>SKU</th>
<th>Category</th>
<th>Price</th>
<th>Stock</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="media">
<div class="media-left">
<figure class="image is-48x48">
<img src="product1.jpg" alt="Product">
</figure>
</div>
<div class="media-content">
<p class="has-text-weight-semibold">Wireless Headphones</p>
<p class="is-size-7 has-text-grey">Premium sound quality</p>
</div>
</div>
</td>
<td>WH-2024</td>
<td>Electronics</td>
<td>
<span class="has-text-weight-bold">$99.99</span>
</td>
<td>
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">45 units</div>
</div>
<div class="level-right">
<div class="level-item">
<progress class="progress is-small is-success" value="45" max="100">45%</progress>
</div>
</div>
</div>
</td>
<td>
<span class="tag is-success">In Stock</span>
</td>
</tr>
<tr>
<td>Laptop Stand</td>
<td>LS-101</td>
<td>Accessories</td>
<td>$29.99</td>
<td>
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">3 units</div>
</div>
<div class="level-right">
<div class="level-item">
<progress class="progress is-small is-warning" value="15" max="100">15%</progress>
</div>
</div>
</div>
</td>
<td>
<span class="tag is-warning">Low Stock</span>
</td>
</tr>
<tr>
<td>Gaming Mouse</td>
<td>GM-305</td>
<td>Gaming</td>
<td>$49.99</td>
<td>
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">0 units</div>
</div>
</div>
</td>
<td>
<span class="tag is-danger">Out of Stock</span>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="6" class="has-text-right">
<strong>Total Products:</strong> 3
</td>
</tr>
</tfoot>
</table>
</div>
</div>Financial Transactions Table
<table class="table is-fullwidth is-hoverable">
<thead>
<tr class="has-background-dark has-text-white">
<th>Date</th>
<th>Description</th>
<th>Category</th>
<th class="has-text-right">Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>2024-01-15</td>
<td>Website Hosting</td>
<td>
<span class="tag is-info">Business</span>
</td>
<td class="has-text-right has-text-danger">-$29.99</td>
<td>
<span class="icon has-text-success">
<i class="fas fa-check-circle"></i>
</span>
<span>Completed</span>
</td>
</tr>
<tr>
<td>2024-01-14</td>
<td>Freelance Payment</td>
<td>
<span class="tag is-success">Income</span>
</td>
<td class="has-text-right has-text-success">+$1,250.00</td>
<td>
<span class="icon has-text-success">
<i class="fas fa-check-circle"></i>
</span>
<span>Completed</span>
</td>
</tr>
<tr>
<td>2024-01-13</td>
<td>Software Subscription</td>
<td>
<span class="tag is-warning">Software</span>
</td>
<td class="has-text-right has-text-danger">-$99.00</td>
<td>
<span class="icon has-text-warning">
<i class="fas fa-clock"></i>
</span>
<span>Pending</span>
</td>
</tr>
</tbody>
<tfoot>
<tr class="has-background-light">
<td colspan="3" class="has-text-weight-bold">Total</td>
<td class="has-text-right has-text-weight-bold has-text-success">+$1,121.01</td>
<td></td>
</tr>
</tfoot>
</table>Best Practices
- Always wrap tables in
.table-containerfor proper overflow handling - Use
is-stripedandis-hoverablefor better readability - Make tables responsive with horizontal scrolling on mobile
- Use appropriate header colors to distinguish from data rows
- Align numerical data to the right for easier comparison
- Use tags and icons to represent status and categories visually
- Implement sorting and filtering for large datasets
- Consider pagination for tables with many rows
Accessibility: Always include proper table headers with
<th>elements, use scope="col" for column headers and scope="row" for row headers when applicable, and provide captions for complex tables.Next: Bulma Tabs Component