The <luna-data-grid> component provides a full-featured data table with sorting, filtering, row selection, and pagination.
Paths
/lunadom/components/data-grid/data-grid.js REQUIRED
Basic Grid
With Filter
Selectable Rows
No rows selected
Customization
Attributes
page-size - Rows per page (default: 10, set 0 to disable)
filter - Initial filter query string
selectable - Enable row checkboxes and selection
striped - Alternating row backgrounds
no-border - Remove outer border and radius
loading - Shows skeleton loading state
empty-label - Text when no results (default: "No results")
Properties
columns - Array of column definitions (JS only)
rows - Array of data objects (JS only)
selected - Set of selected row indices (read-only)
CSS Variables
--luna-grid-bg - Card background
--luna-grid-border - Border color
--luna-grid-header-bg - Header background
--luna-grid-row-hover - Row hover background
--luna-grid-row-selected - Selected row background
--luna-grid-accent - Sort arrow/checkbox accent
Events
luna-sort - sort column or direction changes.
{ key: string, direction: 'asc'|'desc' }
luna-filter - filter query changes.
{ query: string, count: number }
luna-select - row selection changes.
{ selected: number[], rows: object[] }
luna-page - active page changes.
{ page: number, pageSize: number, total: number }
luna-row-click - row is clicked (not on an interactive child).
{ index: number, row: object }
Example Code
<!-- Basic grid -->
<luna-data-grid id="grid"></luna-data-grid>
<script>
const grid = document.getElementById('grid');
// Define columns
grid.columns = [
{ key: 'name', label: 'Name', sortable: true, filterable: true },
{ key: 'email', label: 'Email', sortable: true, filterable: true },
{ key: 'role', label: 'Role', sortable: true, width: '120px' }
];
// Set data
grid.rows = [
{ name: 'Alice', email: 'alice@example.com', role: 'Admin' },
{ name: 'Bob', email: 'bob@example.com', role: 'User' }
];
</script>
<!-- With filter -->
<luna-input id="filter" placeholder="Search..."></luna-input>
<luna-data-grid id="grid" striped></luna-data-grid>
<script>
const grid = document.getElementById('grid');
const filter = document.getElementById('filter');
grid.columns = [
{ key: 'name', label: 'Name', sortable: true, filterable: true },
{ key: 'salary', label: 'Salary', sortable: true, align: 'right',
render: (val) => `$${val.toLocaleString()}` }
];
grid.rows = [
{ name: 'John', salary: 95000 },
{ name: 'Jane', salary: 105000 }
];
// Connect filter input
grid.connectFilter(filter);
</script>
<!-- Selectable rows -->
<luna-data-grid id="grid" selectable></luna-data-grid>
<script>
const grid = document.getElementById('grid');
grid.columns = [...];
grid.rows = [...];
// Listen to selection changes
grid.addEventListener('luna-select', (e) => {
console.log('Selected rows:', e.detail.selected);
console.log('Selected data:', e.detail.rows);
});
</script>
<!-- Custom page size -->
<luna-data-grid page-size="20"></luna-data-grid>
<!-- Disable pagination -->
<luna-data-grid page-size="0"></luna-data-grid>
<!-- Loading state -->
<luna-data-grid loading></luna-data-grid>
<!-- Custom column definition -->
<script>
grid.columns = [
{
key: 'name', // Data property key (required)
label: 'Full Name', // Header text
sortable: true, // Enable sorting
filterable: true, // Include in filter
width: '200px', // CSS width
align: 'left', // left, center, right
render: (value, row, index) => {
// Custom HTML rendering
return `<strong>${value}</strong>`;
}
}
];
</script>
<!-- Event listeners -->
<script>
grid.addEventListener('luna-sort', (e) => {
console.log('Sorted by:', e.detail.key, e.detail.direction);
});
grid.addEventListener('luna-filter', (e) => {
console.log('Filter query:', e.detail.query);
console.log('Matching rows:', e.detail.count);
});
grid.addEventListener('luna-page', (e) => {
console.log('Page:', e.detail.page);
});
grid.addEventListener('luna-row-click', (e) => {
console.log('Clicked row:', e.detail.index, e.detail.row);
});
</script>