
AvalynxDataTable is a vanilla JavaScript data table component for the Bootstrap 5 framework that displays records fetched from a server API.
It supports searching, column sorting, pagination, and horizontally scrollable tables with fixed edge columns.
Each interaction sends a request to your endpoint. The server returns matching rows, column definitions, and record counts in the required JSON format.
Features
- Ctrl-click or Shift-click supports sorting by multiple columns.
- Configurable page sizes and neighboring pagination links.
- Debounced search input with adjustable delay.
- Fixed start and end columns for horizontally scrolling tables.
- Hidden columns and custom classes for headers, rows, and cells.
- Plain-text cells or explicit HTML content for action links.
- Custom English or translated labels and entry-count messages.
- Optional integration with AvalynxLoader and AvalynxTable.
- Independent table instances on a single page.
How To Use It
Installation
Load the Bootstrap stylesheet and JavaScript bundle plus the AvalynxDataTable CSS and browser build.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/avalynx-datatable/dist/css/avalynx-datatable.css"> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/avalynx-datatable/dist/js/avalynx-datatable.js"></script>
You can also install the package with NPM and import its ES module and styles into your project.
npm install avalynx-datatable
import { AvalynxDataTable } from 'avalynx-datatable';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'avalynx-datatable/dist/css/avalynx-datatable.css';
Basic Usage
Create an empty container, then initialize the table after that element exists.
Set
apiUrlto your own endpoint. The endpoint must implement the request and response formats described next.
<div id="staff-table"></div>
const staffTable = new AvalynxDataTable('staff-table', {
apiUrl: '/api/staff',
perPage: 10,
sorting: { name: 'asc' }
});
Server Request And JSON Response
AvalynxDataTable sends URL-encoded form parameters. The default HTTP method is POST. A GET request places the parameters in the query string. The endpoint must implement filtering, sorting, and pagination.
| Request field | Meaning |
|---|---|
search | Current search text. |
sorting | JSON-encoded object of column IDs and asc or desc directions. |
page | Requested page number. |
perpage | Requested records per page. |
searchisnew | 1 after the search text changes, otherwise 0. |
Return the column definitions, current-page rows, count metadata, and active sorting as JSON. Include both count.total and count.all with the unfiltered record count.
Set count.filtered after applying the search and return only the selected page. Include search.value if your endpoint echoes the search term.
A column with
raw: trueinserts HTML directly into cells, so its values must come from a trusted or sanitized source.
{
"head": {
"columns": [
{ "id": "id", "name": "ID", "sortable": true, "fixed": "start" },
{ "id": "name", "name": "Name", "sortable": true },
{ "id": "department", "name": "Department" },
{ "id": "actions", "name": "Actions", "raw": true, "fixed": "end" }
]
},
"data": [
{
"data": {
"id": 101,
"name": "Taylor Reed",
"department": "Support",
"actions": "<a href=\"/staff/101/edit\" class=\"btn btn-sm btn-primary\">Edit</a>"
},
"class": "",
"data_class": { "actions": "text-end" }
}
],
"count": {
"total": 1,
"all": 1,
"filtered": 1,
"start": 1,
"end": 1,
"perpage": 10,
"page": 1
},
"sorting": { "name": "asc" },
"search": { "value": "" }
}
Advanced Usages
Pass API Parameters And Use GET
Use apiParams for additional server filters. apiMethod: 'GET' sends the table state and custom parameters in the URL query string.
Pass a URL that does not already contain a query string, since this version appends
?directly.
new AvalynxDataTable('orders-table', {
apiUrl: '/api/orders',
apiMethod: 'GET',
apiParams: { status: 'pending' },
perPage: 25,
listPerPage: [10, 25, 50]
});
Customize The Table Labels
Replace the Basic Usage initializer with this version to customize labels and count text. The third constructor argument accepts strings and two entry-summary callbacks.
new AvalynxDataTable('staff-table', {
apiUrl: '/api/staff'
}, {
showLabel: 'Rows',
entriesLabel: 'per page',
searchLabel: 'Find staff',
previousLabel: 'Back',
nextLabel: 'Next',
showingEntries: (start, end, total) =>
`${start}-${end} of ${total} records`,
showingFilteredEntries: (start, end, filtered, total) =>
`${start}-${end} of ${filtered} matches (${total} records)`
});
Integrate AvalynxLoader And AvalynxTable
new AvalynxDataTable('staff-table', {
apiUrl: '/api/staff',
className: 'avalynx-table avalynx-table-md table table-striped table-bordered align-middle',
loader: new AvalynxLoader('#staff-table', {
className: 'spinner-border text-primary'
})
});
Constructor And Configuration Reference
Configuration Options
apiUrl(string, default''): Endpoint that returns the data table JSON response.apiMethod(string, default'POST'): HTTP method. The built-in request handling recognizes'GET'and otherwise sends URL-encoded parameters in a request body.apiParams(object, default{}): Additional request parameters. Avoid reusing the table’s own request-field names.sorting(object, default[]): Initial column ID to sort-direction map, for example{ name: 'asc', age: 'desc' }. The library initializes the unset state as an empty array.currentPage(number, default1): Initial page number.search(string, default''): Initial search string.searchWait(number, default800): Input debounce delay in milliseconds.listPerPage(number[], default[10, 25, 50, 100]): Page-size choices in the dropdown.perPage(number, default10): Initial page size. If its value is absent fromlistPerPage, the component selects the first available choice.className(string, default'table table-striped table-bordered table-responsive align-middle'): CSS classes applied to the generated<table>.breakpoint(string, default'md'): Bootstrap responsive breakpoint for the layout of the top and bottom controls.paginationPrevNext(boolean, defaulttrue): Display previous and next page links.paginationRange(number, default2): Number of page links displayed on either side of the current page.loader(object, defaultnull): Optional AvalynxLoader instance. The component controls itsloadproperty during requests.
Language Options And Callbacks
showLabel(string, default'Show'): Text before the page-size selector.entriesLabel(string, default'entries'): Text after the page-size selector.searchLabel(string, default'Search'): Label for the search field.previousLabel(string, default'Previous'): Previous-page label.nextLabel(string, default'Next'): Next-page label.showingEntries(function(start, end, total), default`Showing ${start} to ${end} of ${total} entries`): Entry summary when the record count is unfiltered.showingFilteredEntries(function(start, end, filtered, total), default`Showing ${start} to ${end} of ${filtered} entries (filtered from ${total} total entries)`): Entry summary when a filter changes the record count.
JSON Response Reference
Column Definitions: `head.columns[]`
| Field | Description |
|---|---|
id | Column identifier used to read cell data and process sorting. |
name | Displayed header text. |
sortable | Enables clickable sorting when true. |
hidden | Hides the column when true. |
raw | Interprets cell values as HTML when true. By default cell values are rendered as text. |
class | Extra CSS class for the column’s header and cells. |
fixed | Pins a column to 'start' or 'end' during horizontal scrolling. |
Row Data: `data[]`
| Field | Description |
|---|---|
data | Object whose properties correspond to column IDs. |
config | Optional metadata associated with a row. The table renderer does not act on it. |
class | CSS class applied to the <tr> element. |
data_class | Object mapping column IDs to extra cell CSS classes. |
Counts And Table State
| Field | Description |
|---|---|
count.total | Unfiltered record count in the response format. |
count.all | Unfiltered total used by the 1.0.7 entry-summary renderer. |
count.filtered | Number of records matching the active filter. |
count.start | First record index on the current page. |
count.end | Last record index on the current page. |
count.perpage | Page size returned by the server. |
count.page | Current page number returned by the server. |
sorting | Object keyed by column ID with 'asc' or 'desc' values. |
search.value | Search string echoed by the endpoint when included. |
Instance Methods
staffTable.refresh(); // Run when the table is no longer needed. staffTable.destroy();
Styling And Fixed Columns
Use className to set Bootstrap table classes. API responses can also style headers and cells with head.columns[].class, rows with data[].class, and individual cells with data[].data_class.
Set fixed: 'start' or fixed: 'end' in a column definition for sticky cells inside the horizontal scroll container. Avoid assigning the same edge to several columns since each edge uses one sticky position.
Alternatives & Related Resources
- Full-featured Interactive Data Table JavaScript Library – simple-datatables
- Sortable, Editable, Filterable Data Grid Web Component – data-grid.js
- Vanilla JavaScript Table Enhancement: Search, Sort, Paginate
- Full-featured Data Table JavaScript Library – Grid.js
FAQs
Q: Can AvalynxDataTable enhance an existing HTML table?
A: It creates its own table inside the container passed to the constructor. An API endpoint must return the column definitions and current rows in the required JSON format.
Q: Why does the entry summary display undefined?
A: The entry summary reads count.all. Return it as a number alongside count.total and count.filtered.
Q: Why does an endpoint that returns a JSON array fail?
A: The component expects an object with head.columns, data, count, and sorting. Transform a plain array into that response format on the server.
Q: Does the table stack rows on small screens?
A: The default layout scrolls horizontally. Use the optional AvalynxTable library for responsive table behavior.







