Skip to content

Remote Table

A powerful component for displaying remote data in a table format with built-in pagination, search, sorting, and customizable rendering. The Remote Table component fetches data from remote APIs and provides a flexible interface for displaying tabular data with full control over pagination modes.

  • Table component (for base table styles)
  • Pagination component
  • Input component (for search functionality)
  • Select component (for rows count selection)
<div data-role="remote-table"
data-url="https://api.example.com/data"
data-key-data="items"
data-fields="id, name, email">
</div>

Page-based Pagination (pageMode=“page”)

Section titled “Page-based Pagination (pageMode=“page”)”
<div data-role="remote-table"
data-page-mode="page"
data-offset="1"
data-key-offset="page"
data-key-data="data"
data-key-limit="perPage"
data-key-total="totalProducts"
data-fields="id, title, price"
data-url="https://api.example.com/products">
</div>

Offset-based Pagination (pageMode=“offset” - default)

Section titled “Offset-based Pagination (pageMode=“offset” - default)”
<div data-role="remote-table"
data-page-mode="offset"
data-key-offset="skip"
data-key-limit="limit"
data-key-data="products"
data-key-total="total"
data-fields="id, title, price"
data-url="https://api.example.com/products">
</div>
<div data-role="remote-table"
data-caption="Products"
data-url="https://dummyjson.com/products"
data-url-search="https://dummyjson.com/products/search"
data-key-offset="skip"
data-key-limit="limit"
data-key-data="products"
data-key-total="total"
data-key-sort="sortBy"
data-key-order="order"
data-key-search="q"
data-fields="id, title, price, discountPercentage"
data-sortable-fields="id, title, price, discountPercentage"
data-col-size="30,,150,150"
data-captions="ID, Title, Price, Discount"
data-sort="id"
data-rows="10"
data-rows-steps="10,25,50,100"
data-page-mode="offset"
data-on-draw-cell="drawCell"
data-cls-table="table-border striped row-hover responsive-sm"
data-cls-pagination="mt-4 d-flex flex-justify-center">
</div>
<div class="d-flex flex-row gap-2">
<input type="text" id="search" placeholder="Search...">
<select id="rows"></select>
</div>
<div data-role="remote-table"
data-url="https://api.example.com/data"
data-search-control="#search"
data-rows-count-control="#rows"
data-key-data="items">
</div>
const table = Metro.makePlugin("#myTable", "remote-table", {
url: "https://api.example.com/data",
pageMode: "page",
keyData: "items",
fields: "id, name, email"
});
ParameterTypeDefaultDescription
captionstring""Table caption text
urlstring""Primary URL for data fetching
urlSearchstring""Alternative URL for search requests
methodstring”GET”HTTP method for requests
limitnumber10Number of records per page
offsetnumbernullStarting offset/page (auto-calculated based on pageMode)
fieldsstring""Comma-separated list of fields to display
sortableFieldsstring""Comma-separated list of sortable fields
colSizestring""Comma-separated list of column widths
sortstring""Default sort field
sortOrderstring”asc”Default sort order (asc/desc)
captionsstringnullComma-separated list of column headers
keyLimitstring""API parameter name for limit
keyOffsetstring""API parameter name for offset/page
keyTotalstring""API response key for total count
keyDatastring""API response key for data array
keySortstring""API parameter name for sort field
keyOrderstring""API parameter name for sort order
keySearchstring”q”API parameter name for search query
shortPaginationbooleanfalseUse simple prev/next pagination
rowsnumber10Initial rows per page
rowsStepsstring”10,25,50,100”Available rows per page options
showServiceBlockbooleantrueShow search and controls block
quickSearchbooleantrueShow search input
selectOrderbooleantrueShow sort controls
selectCountbooleantrueShow rows count selector
showPaginationbooleantrueShow pagination controls
paramsobjectnullAdditional parameters to send with requests
searchControlstringnullSelector for external search control
rowsCountControlstringnullSelector for external rows count control
searchThresholdnumber3Minimum characters to trigger search
rowsLabelstring""Label for rows count selector
searchLabelstring""Label for search input
pageModestring”offset”Pagination mode: “offset” or “page”
clsTablestring""CSS classes for table element
clsRowstring""CSS classes for table rows
clsCellstring""CSS classes for table cells
clsHeadstring""CSS classes for table header
clsPaginationstring""CSS classes for pagination

The pageMode parameter is crucial for API compatibility and determines how pagination values are calculated and sent to your server:

  • Offset Calculation: Starts from 0, increments by limit value
  • API Requests: Sends offset values (0, 10, 20, 30…)
  • Use Case: APIs that expect offset-based pagination
  • Example: ?limit=10&skip=20 (for page 3 with 10 items per page)
  • Page Calculation: Starts from 1, increments by 1
  • API Requests: Sends page numbers (1, 2, 3, 4…)
  • Use Case: APIs that expect page-based pagination
  • Example: ?perPage=10&page=3 (for page 3 with 10 items per page)

Important: When using pageMode="page", make sure to:

  1. Set data-offset="1" to start from page 1
  2. Use appropriate keyOffset parameter name (e.g., “page”)
  3. Ensure your API expects page numbers, not offset values
  • addParam(key, value) - Add a single parameter to API requests.
  • addParams(params) - Add multiple parameters to API requests.
  • clearParams() - Clear all additional parameters.
  • load(append) - Reload data from the API.
  • destroy() - Remove the component and clean up.
const table = Metro.getPlugin('#myTable', 'remote-table');
// Add search parameter
table.addParam('category', 'electronics');
// Add multiple parameters
table.addParams({
minPrice: 100,
maxPrice: 500
});
// Reload data
table.load();
// Clear parameters
table.clearParams();
EventDescription
onBeforeLoadFired before data loading, allows URL modification
onLoadFired after data is loaded, allows data transformation
onDrawRowFired when drawing each table row
onDrawCellFired when drawing each table cell
onDrawHeadCellFired when drawing each header cell
onTableCreateFired when the table component is created
function beforeLoad(url, table) {
console.log('Loading from:', url);
return url; // Return modified URL if needed
}
function onLoad(data, table) {
console.log('Data loaded:', data);
return data; // Return transformed data if needed
}
function drawCell(cell, value, fieldName, record, index) {
if (fieldName === 'price') {
cell.innerHTML = `$${value}`;
}
}
<div data-role="remote-table"
data-on-before-load="beforeLoad"
data-on-load="onLoad"
data-on-draw-cell="drawCell">
</div>
VariableDefaultDescription
--remote-table-order-block-size200pxWidth of the sort controls block
--remote-table-count-block-size140pxWidth of the rows count selector block
#my-table {
--remote-table-order-block-size: 250px;
--remote-table-count-block-size: 160px;
}
  • .remote-table - Main component container
  • .table-component - Applied to the main element
  • .service-block - Container for search and controls
  • .search-block - Container for search input
  • .count-block - Container for rows count selector
  • .order-block - Container for sort controls
  • .table-pagination - Pagination container
  • .data-cell-{fieldName} - Applied to each data cell based on field name
  • .head-cell-{fieldName} - Applied to each header cell based on field name
  • .sortable-column - Applied to sortable column headers
  • .sort-asc - Applied to ascending sorted columns
  • .sort-desc - Applied to descending sorted columns

Example 1: Page-based API (like many REST APIs)

Section titled “Example 1: Page-based API (like many REST APIs)”
<!-- For APIs that expect: /api/products?page=1&perPage=10 -->
<div data-role="remote-table"
data-page-mode="page"
data-offset="1"
data-key-offset="page"
data-key-limit="perPage"
data-url="/api/products">
</div>

Example 2: Offset-based API (like DummyJSON)

Section titled “Example 2: Offset-based API (like DummyJSON)”
<!-- For APIs that expect: /api/products?skip=0&limit=10 -->
<div data-role="remote-table"
data-page-mode="offset"
data-key-offset="skip"
data-key-limit="limit"
data-url="/api/products">
</div>
const table = Metro.getPlugin('#myTable', 'remote-table');
// Switch to page mode
table.options.pageMode = 'page';
table.options.keyOffset = 'page';
table.offset = 1;
table.load();
// Switch to offset mode
table.options.pageMode = 'offset';
table.options.keyOffset = 'skip';
table.offset = 0;
table.load();
  • Use pageMode="page" when your API expects page numbers (1, 2, 3…)
  • Use pageMode="offset" when your API expects offset values (0, 10, 20…)
  • Always verify your API documentation to choose the correct mode
  • Test pagination with your API to ensure correct behavior
  • Always specify keyData to tell the component where to find the data array in the API response
  • Use keyTotal for proper pagination when your API provides total count
  • Implement onDrawCell for custom cell formatting
  • Use external controls for better UX when integrating with existing forms
  • Set appropriate searchThreshold to avoid excessive API calls
  • Use shortPagination for mobile-friendly interfaces
  • Always handle loading states and errors in your onBeforeLoad and onLoad callbacks
  • The component automatically handles debounced search to prevent excessive API calls
  • Sorting is handled client-side by sending sort parameters to the API
  • The component supports both simple prev/next pagination and full page number pagination
  • All API parameters are URL-encoded automatically
  • The component integrates seamlessly with Metro UI’s theming system
  • Custom cell rendering allows for complex data presentation including HTML content