NoundryTable - Advanced Data Grid
A powerful, server-side paginated data grid inspired by svelte-tablecn. All parameters are sent to the API for filtering, sorting, and pagination.
User Management
Full-featured table with search, sorting, pagination, selection, and export.
Users
Manage your team members
Showing to
of
results
No results
View Code
<noundry-data-grid
api-url="/api/users"
title="Users"
description="Manage your team members"
page-size="10"
page-size-options="5,10,25,50"
default-sort-column="name"
default-sort-direction="asc"
enable-search="true"
enable-sorting="true"
enable-selection="true"
enable-multi-select="true"
enable-column-toggle="true"
enable-export="true"
enable-refresh="true"
hoverable="true"
striped="false"
row-id-property="id">
<noundry-data-grid-col key="id" label="ID" sortable="true" width="80px" align="center" />
<noundry-data-grid-col key="name" label="Name" sortable="true" />
<noundry-data-grid-col key="email" label="Email" sortable="true" href="mailto:{email}" />
<noundry-data-grid-col key="department" label="Department" sortable="true" />
<noundry-data-grid-col key="status" label="Status" type="badge"
badge-variants='{"active":"success","inactive":"error","pending":"warning"}' />
<noundry-data-grid-col key="salary" label="Salary" type="currency" sortable="true" align="right" />
<noundry-data-grid-col key="hireDate" label="Hire Date" type="date" sortable="true" />
<noundry-data-grid-col key="active" label="Active" type="boolean" align="center" />
</noundry-data-grid>
Product Inventory
Compact table with striped rows and different column configurations.
View Code
<noundry-data-grid
api-url="/api/products"
title="Products"
page-size="10"
enable-search="true"
enable-sorting="true"
enable-pagination="true"
striped="true"
row-height="compact"
row-id-property="id">
<noundry-data-grid-col key="sku" label="SKU" sortable="true" width="120px" />
<noundry-data-grid-col key="name" label="Product Name" sortable="true" />
<noundry-data-grid-col key="category" label="Category" sortable="true" />
<noundry-data-grid-col key="price" label="Price" type="currency" sortable="true" align="right" />
<noundry-data-grid-col key="stock" label="Stock" type="number" sortable="true" align="right" />
<noundry-data-grid-col key="status" label="Status" type="badge"
badge-variants='{"in_stock":"success","low_stock":"warning","out_of_stock":"error"}' />
<noundry-data-grid-col key="createdAt" label="Created" type="date" sortable="true" />
</noundry-data-grid>
API Integration
The NoundryDataGrid component sends the following query parameters to your API:
GET /api/users?page=1&pageSize=10&sortColumn=name&sortDirection=asc&search=john
Expected Response Format
{
"data": [
{ "id": 1, "name": "John Doe", "email": "john@example.com", ... }
],
"total": 150
}
Example C# API Controller
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
[HttpGet]
public IActionResult GetUsers(
int page = 1,
int pageSize = 10,
string? sortColumn = null,
string? sortDirection = "asc",
string? search = null)
{
var query = _dbContext.Users.AsQueryable();
// Apply search filter
if (!string.IsNullOrEmpty(search))
{
query = query.Where(u =>
u.Name.Contains(search) ||
u.Email.Contains(search));
}
// Apply sorting
query = sortColumn switch
{
"name" => sortDirection == "desc"
? query.OrderByDescending(u => u.Name)
: query.OrderBy(u => u.Name),
"email" => sortDirection == "desc"
? query.OrderByDescending(u => u.Email)
: query.OrderBy(u => u.Email),
_ => query.OrderBy(u => u.Id)
};
var total = query.Count();
var data = query
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
return Ok(new { data, total });
}
}
Column Types
text
Default. Displays plain text.
number
Formats numbers with locale separators.
currency
Formats as currency (default USD).
date
Formats as localized date.
datetime
Formats as localized date and time.
boolean
Shows checkmark or X icon.
badge
Colored badge with variant mapping.
Accessing Selected IDs (Client-Side)
Use Alpine.js to access the selected row IDs from JavaScript:
// Get the data grid element by ID
const grid = document.getElementById('users-grid');
// Access the Alpine.js component data
const data = Alpine.$data(grid);
// Get selected IDs as an array
const selectedIds = Array.from(data.selectedRows);
console.log('Selected IDs:', selectedIds);
// Get full row data for selected items
const selectedRows = data.data.filter(row => data.isSelected(row));
console.log('Selected Rows:', selectedRows);
// Clear all selections
data.clearSelection();
// Check selection count
const count = data.selectedRows.size;
console.log(`${count} items selected`);
Example: Bulk Actions with Selected IDs
// Function to delete selected users
async function deleteSelectedUsers() {
const grid = document.getElementById('users-grid');
const data = Alpine.$data(grid);
const selectedIds = Array.from(data.selectedRows);
if (selectedIds.length === 0) {
alert('No users selected');
return;
}
if (!confirm(`Delete ${selectedIds.length} user(s)?`)) {
return;
}
try {
const response = await fetch('/api/users/bulk-delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: selectedIds })
});
if (response.ok) {
// Refresh the grid after deletion
data.refresh();
data.clearSelection();
}
} catch (error) {
console.error('Delete failed:', error);
}
}