Implementing Interactive Data Grids with bootstrap-table: Declarative and Programmatic Patterns

Overview of Configuration Approaches

The bootstrap-table plugin provides a flexible architecture for rendering server-driven and client-side data grids. It natively supports two distinct initialization strategies: HTML attribute-driven declarative configuration and JavaScript-based programmatic instantiation. This guide demonstrates both patterns using plugin version 1.15.5, Bootstrap 4.3.1, and jQuery 3.4.1. Standard CSS and script dependencies are assumed to be loaded prior to initialization.

  1. Declarative Configuration

Declarative setup relies on data-* attributes atttached directly to the <table> element. This approach minimizes boilerplate JavaScript and is ideal for standard pagination, sorting, and remote data fetching. Comprehensive attribute references are available in the official API documentation.


<div class="data-container">
  <table id="inventory-grid"
         data-toggle="table"
         data-pagination="true"
         data-side-pagination="server"
         data-page-size="10"
         data-query-params="assembleSearchParams"
         data-url="/api/products/list">
    <thead>
      <tr>
        <th data-field="item_name">Product Name</th>
        <th data-field="category">Category</th>
        <th data-field="unit_price">Price</th>
        <th data-field="stock_level">Stock</th>
        <th data-field="created_at">Date Added</th>
        <th data-field="item_id" data-width="160" data-formatter="generateActionButtons">Actions</th>
      </tr>
    </thead>
  </table>
</div>

Column rendering logic is attached via the data-formatter attribute. The corresponding handler receives the cell value, row object, and index:


function generateActionButtons(cellValue, rowData, rowIndex) {
  const disabledState = (cellValue === 'archived') ? 'disabled' : '';
  return `
    <button class="btn btn-sm btn-info" ${disabledState} onclick="editProduct('${rowData.item_id}')">Edit</button>
    <button class="btn btn-sm btn-danger" ${disabledState} onclick="removeProduct('${rowData.item_id}')">Delete</button>
    <button class="btn btn-sm btn-secondary" onclick="previewProduct('${rowData.item_id}')">Details</button>
  `;
}

Server-side pagination requires mapping internal request parameters to backend expectations. The data-query-params handler transforms the plugin's payload:


function assembleSearchParams(requestConfig) {
  return {
    skip: requestConfig.offset,
    take: requestConfig.limit,
    sortField: requestConfig.sort,
    sortOrder: requestConfig.order,
    pageIndex: (requestConfig.offset / requestConfig.limit) + 1,
    pageSize: requestConfig.limit,
    categoryFilter: document.getElementById('filter-category').value,
    nameFilter: document.getElementById('filter-name').value
  };
}

Characteristics: The plugin parses DOM attributes and automatically binds event listeners upon document ready. This pattern accelerates development and keeps markup readable. However, the automatic initialization trigger can be restrictive when conditional loading or dynamic DOM injection is required.

  1. Programmatic Initialization

Programmatic instantiation passes a configuraton object directly to the jQuery plugin method. This approach exposes the full lifecycle of the table instance and is better suited for complex UI workflows or framework integrations. Default option structures can be inspected in the library's source constants.


$('#performance-grid').bootstrapTable({
  url: 'data/metrics.json',
  method: 'GET',
  pagination: true,
  pageNumber: 1,
  pageSize: 8,
  uniqueId: 'record_id',
  columns: [
    { field: 'record_id', visible: false },
    { field: 'employee_name', title: 'Staff Member' },
    { field: 'department', title: 'Division' },
    { field: 'start_date', title: 'Hire Date' },
    { field: 'quarterly_score', title: 'Score', formatter: (value, row, index) => {
      const styleColor = value >= 75 ? 'color: #28a745;' : 'color: #dc3545;';
      return `<span style="${styleColor}">${value}</span>`;
    }},
    { field: 'record_id', title: 'Management', formatter: (value, row) => {
      return `<button onclick="updateRecord('${value}')">Update</button> 
              <button onclick="deleteRecord('${value}')">Delete</button>`;
    }}
  ]
});

Custom AJAX Execution

When default fetch behavior conflicts with legacy APIs or requires custom headers/authentication, the data-ajax attribute can be paired with a custom execution handler. The handler must invoke the success callback with the expected response shape.


function executeCustomPagination(fetchOptions) {
  $.ajax({
    url: '/api/metrics/fetch',
    type: 'POST',
    dataType: 'json',
    data: {
      page: (fetchOptions.data.offset / fetchOptions.data.limit) + 1,
      size: fetchOptions.data.limit,
      deptFilter: $('#filter-dept').val(),
      statusFilter: $('#filter-status').val()
    },
    success: (response, status, xhr) => {
      if (response.code === 200) {
        fetchOptions.success({
          total: response.payload.totalCount,
          rows: response.payload.items
        }, 'ok', xhr);
      } else {
        console.warn(response.message);
      }
    },
    error: (xhr, status, err) => {
      console.error('Network failure:', status);
      fetchOptions.success({ total: 0, rows: [] }, 'ok', xhr);
    }
  });
}

Characteristics: Programmatic setup grants explicit control over initialization timing, column mapping, and data transformation. The trade-off is increased verbosity and manual event wiring copmared to the declarative alternative.

Implementation Prerequisites

  • Foundational knowledge of ES6 JavaScript, including object destructuring, arrow functions, and DOM event handling.
  • Familiarity with jQuery selectors, promise-like AJAX patterns, and asynchronous data flow.
  • Systematic review of official documentation for table options, column definitions, and pagination contracts.

Tags: bootstrap-table jquery data-grids client-side-rendering ajax-pagination

Posted on Sat, 26 Sep 2026 16:12:12 +0000 by DJ Unique