Responsive Bootstrap Table with Pagination, Search and Sorting – 8 Complete Examples

|

A complete guide to building a responsive Bootstrap table with pagination, search, and sorting using Bootstrap 5 and vanilla JavaScript — no heavy plugins required. Eight practical examples from a basic Bootstrap table example to a fully-featured bootstrap data table with live filtering, column sorting, and mobile responsiveness.

Bootstrap Table
Search + Filter
Pagination
Column Sorting
Mobile Responsive

If you prefer video tutorials, you can watch the full example here showing how to create responsive bootstrap table with pagination, search and sorting.

Introduction

Data tables are one of the most common UI components in any web application — dashboards, admin panels, CRMs, reports. A plain HTML table works, but users expect more: the ability to search through rows, sort by column, and navigate large datasets with pagination. Adding all three to a bootstrap 5 table responsive layout without a library takes about 150 lines of vanilla JavaScript — and it’s completely worth understanding before reaching for a plugin.

This tutorial builds a responsive bootstrap table with pagination search sorting from scratch, explaining each feature individually before combining everything into one production-ready component. Every example includes a live preview and complete copy-paste code.

What you’ll need

Bootstrap 5 CSS (via CDN — no installation required), and a basic HTML file. No npm, no build tools, no framework. All JavaScript in this guide is vanilla ES6 — no jQuery dependency.

Why Use Responsive Tables in Bootstrap

Raw HTML tables break on small screens — columns overflow the viewport, users have to scroll horizontally to see data, and the layout becomes unreadable. The bootstrap 5 table responsive wrapper solves this with a single CSS class that constrains the overflow and lets the table scroll within its container.

Mobile-First

Horizontal scroll on small screens keeps all columns intact without breaking layout.

Search Filter

Instant row filtering as the user types — works across all columns simultaneously.

Sorted Columns

Click any header to sort ascending/descending. Works with text, numbers, and dates.
ApproachDependenciesBundle sizeBest for
Vanilla JS (this guide)Bootstrap 5 CSS only~150 lines JSFull control, no overhead
bootstrap-table.jsBootstrap 5 + plugin JS~100 KBRapid prototyping
DataTables.jsjQuery + DataTables~300 KB+Complex enterprise tables

Bootstrap Table Basic Example

The simplest bootstrap table example uses Bootstrap’s built-in table classes. table adds base styling, table-striped alternates row colours, table-hover adds a highlight on hover, and table-bordered adds cell borders.

Example 1 of 8 — Bootstrap 5 Basic Table
HTML Bootstrap 5
<!-- Bootstrap 5 CDN (add to <head>) -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
      rel="stylesheet">

<table class="table table-striped table-hover table-bordered">
  <thead class="table-dark">
    <tr>
      <th>#</th>
      <th>Name</th>
      <th>Role</th>
      <th>Department</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td><td>Alice Chen</td>
      <td>Engineer</td><td>Backend</td>
      <td><span class="badge bg-success">Active</span></td>
    </tr>
    <!-- more rows... -->
  </tbody>
</table>

See the result:

Bootstrap table classes reference

table (required base) · table-striped · table-hover · table-bordered · table-sm (compact) · table-dark · table-light · table-striped-columns (column alternating)

Making Bootstrap Table Responsive

Wrapping your table in a div with class table-responsive is all Bootstrap 5 needs to make a table scroll horizontally on small viewports instead of breaking the layout. Bootstrap also provides breakpoint-specific variants.

Example 2 of 8 — Bootstrap 5 Table Responsive Wrapper
HTML Bootstrap 5
<!-- Always responsive (any screen width) -->
<div class="table-responsive">
  <table class="table table-hover">...</table>
</div>

<!-- Only responsive below specific breakpoints -->
<div class="table-responsive-sm">  <!-- scroll on <576px -->
<div class="table-responsive-md">  <!-- scroll on <768px -->
<div class="table-responsive-lg">  <!-- scroll on <992px -->
<div class="table-responsive-xl">  <!-- scroll on <1200px -->
What table-responsive adds (Bootstrap 5 source)
.table-responsive {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

Don’t put dropdowns inside table-responsive

The overflow:auto on the wrapper will clip any dropdown menus that extend beyond the table boundary. Use position: static on the wrapper or move dropdowns outside the scroll area.

Adding Search to Bootstrap Table

Bootstrap table search is not built into Bootstrap itself — it’s implemented with a few lines of JavaScript. The pattern is simple: listen for input events on a text field, then show or hide table rows based on whether any cell contains the search term.

 Example 3 of 8 — Bootstrap 5 Responsive Table with Search Filter
HTML + JavaScript
<!-- Search input -->
<input type="text" id="searchInput"
       class="form-control mb-3"
       placeholder="🔍  Search table...">

<div class="table-responsive">
  <table class="table table-striped table-hover" id="myTable">
    ...
  </table>
</div>

<script>
const searchInput = document.getElementById('searchInput');

searchInput.addEventListener('input', function () {
  const filter = this.value.toLowerCase().trim();
  const rows   = document.querySelectorAll('#myTable tbody tr');

  rows.forEach(row => {
    // Check every cell in the row
    const matches = [...row.cells].some(
      cell => cell.textContent.toLowerCase().includes(filter)
    );
    row.style.display = matches ? '' : 'none';
  });
});
</script>
Responsive bootstrap table with search

Search only specific columns

Replace [...row.cells] with [row.cells[1], row.cells[2]] to search only Name and Role columns, ignoring the # column and Status badges.

Adding Sorting to Bootstrap Table

Bootstrap table sorting requires a click handler on each <th> that reads all rows, sorts them in-memory, and re-inserts them into the DOM. The trick is tracking the current sort column and direction so a second click reverses the order.

Example 4 of 8 — Bootstrap Table Sort Columns Example
JavaScript — Column Sorting
function makeTableSortable(tableId) {
  const table   = document.getElementById(tableId);
  const headers = table.querySelectorAll('thead th');
  let sortCol = null, sortAsc = true;

  headers.forEach((th, colIndex) => {
    th.style.cursor = 'pointer';
    th.innerHTML   += ' <span class="sort-arrow">⇅</span>';

    th.addEventListener('click', () => {
      if (sortCol === colIndex) sortAsc = !sortAsc;
      else { sortCol = colIndex; sortAsc = true; }

      // Update header arrow indicators
      headers.forEach(h => h.classList.remove('asc', 'desc'));
      th.classList.add(sortAsc ? 'asc' : 'desc');
      th.querySelector('.sort-arrow').textContent = sortAsc ? '' : '';

      const tbody = table.querySelector('tbody');
      const rows  = [...tbody.querySelectorAll('tr')];

      rows.sort((a, b) => {
        const aVal = a.cells[colIndex].textContent.trim();
        const bVal = b.cells[colIndex].textContent.trim();

        // Numeric sort if both values are numbers
        const aNum = parseFloat(aVal), bNum = parseFloat(bVal);
        if (!isNaN(aNum) && !isNaN(bNum))
          return sortAsc ? aNum - bNum : bNum - aNum;

        // String sort
        return sortAsc
          ? aVal.localeCompare(bVal)
          : bVal.localeCompare(aVal);
      });

      rows.forEach(row => tbody.appendChild(row));
    });
  });
}

makeTableSortable('myTable');

Adding Pagination to Bootstrap Table

Bootstrap table pagination slices the rows array into pages and renders only the current page’s rows. The pagination controls are plain Bootstrap .pagination nav buttons — no extra library needed for bootstrap table pagination using JavaScript.

Example 5 of 8 — How to Create Responsive Bootstrap Table with Pagination
JavaScript — Pagination Engine
class TablePaginator {
  constructor(tableId, pageSize = 5) {
    this.table      = document.getElementById(tableId);
    this.tbody      = this.table.querySelector('tbody');
    this.allRows    = [...this.tbody.querySelectorAll('tr')];
    this.pageSize   = pageSize;
    this.currentPage = 1;
  }

  get totalPages() {
    return Math.ceil(this.allRows.length / this.pageSize);
  }

  render() {
    const start = (this.currentPage - 1) * this.pageSize;
    const end   = start + this.pageSize;

    // Hide all, show only current page
    this.allRows.forEach((row, i) => {
      row.style.display = (i >= start && i < end) ? '' : 'none';
    });

    this.renderControls();
  }

  renderControls() {
    const nav = document.getElementById(`${this.table.id}-pagination`);
    if (!nav) return;

    nav.innerHTML = '';

    // Previous button
    const prev = createBtn('‹ Prev', () => {
      if (this.currentPage > 1) { this.currentPage--; this.render(); }
    }, this.currentPage === 1);
    nav.appendChild(prev);

    // Page number buttons
    for (let i = 1; i <= this.totalPages; i++) {
      const btn = createBtn(i, () => { this.currentPage = i; this.render(); });
      if (i === this.currentPage) btn.classList.add('active');
      nav.appendChild(btn);
    }

    // Next button
    const next = createBtn('Next ›', () => {
      if (this.currentPage < this.totalPages) { this.currentPage++; this.render(); }
    }, this.currentPage === this.totalPages);
    nav.appendChild(next);
  }
}

function createBtn(label, onClick, disabled = false) {
  const btn = document.createElement('button');
  btn.textContent = label;
  btn.disabled    = disabled;
  btn.addEventListener('click', onClick);
  return btn;
}

const paginator = new TablePaginator('myTable', 5);
paginator.render();
Responsive bootstrap table with pagination

Bootstrap Table with Pagination Search and Sorting – Full Example

This is the complete responsive bootstrap table with pagination search sorting example — combining all three features into a single self-contained component. This is the bootstrap table pagination search sorting pattern you’ll use in production.

Example 6 of 8 — Bootstrap Table with Search, Sorting and Pagination
JavaScript — Full DataTable Class
class BootstrapDataTable {
  constructor({ tableId, pageSize = 5, searchInputId, paginationId, infoId }) {
    this.table     = document.getElementById(tableId);
    this.tbody     = this.table.querySelector('tbody');
    this.allRows   = [...this.tbody.querySelectorAll('tr')];
    this.filtered  = [...this.allRows];
    this.pageSize  = pageSize;
    this.page      = 1;
    this.sortCol   = null;
    this.sortAsc   = true;

    if (searchInputId) this.bindSearch(searchInputId);
    this.bindSort();
    this.paginationEl = document.getElementById(paginationId);
    this.infoEl       = document.getElementById(infoId);
    this.render();
  }

  bindSearch(id) {
    document.getElementById(id).addEventListener('input', e => {
      const q = e.target.value.toLowerCase().trim();
      this.filtered = this.allRows.filter(row =>
        [...row.cells].some(c => c.textContent.toLowerCase().includes(q))
      );
      this.page = 1;   // reset to page 1 on new search
      this.render();
    });
  }

  bindSort() {
    this.table.querySelectorAll('thead th').forEach((th, i) => {
      th.style.cursor = 'pointer';
      th.addEventListener('click', () => {
        this.sortAsc   = this.sortCol === i ? !this.sortAsc : true;
        this.sortCol   = i;
        this.filtered.sort((a, b) => {
          const av = a.cells[i].textContent.trim();
          const bv = b.cells[i].textContent.trim();
          const an = parseFloat(av), bn = parseFloat(bv);
          if (!isNaN(an) && !isNaN(bn))
            return this.sortAsc ? an-bn : bn-an;
          return this.sortAsc ? av.localeCompare(bv) : bv.localeCompare(av);
        });
        this.page = 1;
        this.render();
      });
    });
  }

  render() {
    const start = (this.page - 1) * this.pageSize;
    const end   = start + this.pageSize;
    const total = this.filtered.length;

    // Rebuild tbody with filtered + paginated rows
    this.tbody.innerHTML = '';
    this.filtered.slice(start, end).forEach(row => this.tbody.appendChild(row));

    if (this.infoEl)
      this.infoEl.textContent =
        total === 0 ? 'No results found.'
        : `Showing ${start+1}${Math.min(end,total)} of ${total} entries`;

    this.renderPagination(total);
  }

  renderPagination(total) {
    if (!this.paginationEl) return;
    const pages = Math.ceil(total / this.pageSize);
    this.paginationEl.innerHTML = '';

    const btn = (label, page, disabled, active) => {
      const b = document.createElement('button');
      b.textContent = label; b.disabled = disabled;
      if (active) b.classList.add('active');
      b.addEventListener('click', () => { this.page = page; this.render(); });
      return b;
    };

    this.paginationEl.appendChild(btn('', this.page-1, this.page===1));
    for (let i=1; i<=pages; i++)
      this.paginationEl.appendChild(btn(i, i, false, i===this.page));
    this.paginationEl.appendChild(btn('', this.page+1, this.page===pages));
  }
}

// Initialize
new BootstrapDataTable({
  tableId:       'myTable',
  pageSize:      5,
  searchInputId: 'tableSearch',
  paginationId:  'tablePagination',
  infoId:        'tableInfo'
});
Bootstrap Table with Pagination Search and Sorting

Using Bootstrap Table Plugin (bootstrap-table.js)

bootstrap-table.js is a dedicated plugin that adds bootstrap table pagination search sorting features through HTML data attributes with zero custom JavaScript. It’s ideal for rapid prototyping when you don’t need custom logic.

Example 7 of 8 — Bootstrap Table Plugin
HTML — bootstrap-table.js
<!-- In <head> -->
<link rel="stylesheet"
      href="https://unpkg.com/bootstrap-table@1.22.1/dist/bootstrap-table.min.css">

<!-- In <body> before </body> -->
<script src="https://unpkg.com/bootstrap-table@1.22.1/dist/bootstrap-table.min.js"></script>

<!-- The table — all config via data-* attributes -->
<table
  data-toggle="table"
  data-search="true"
  data-pagination="true"
  data-page-size="5"
  data-sortable="true"
  class="table table-striped table-hover">

  <thead>
    <tr>
      <th data-field="id"         data-sortable="true">#</th>
      <th data-field="name"       data-sortable="true">Name</th>
      <th data-field="role"       data-sortable="true">Role</th>
      <th data-field="department" data-sortable="true">Department</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>1</td><td>Alice Chen</td><td>Engineer</td><td>Backend</td></tr>
    <!-- more rows -->
  </tbody>
</table>

Plugin Pros

+ Zero JavaScript required
+ Many built-in features (export, freeze columns, row detail)
+ Active community and documentation
+ Server-side pagination support

Plugin Cons

– Additional ~100 KB dependency
– Less control over custom behaviour
– Plugin version drift with Bootstrap
– Overkill for simple tables

Styling Bootstrap Table

Bootstrap 5 ships with contextual colour classes for both the table itself and individual rows or cells. Combine these with custom CSS for a polished bootstrap data table that matches your brand.

 Example 8 of 8 — Styled Bootstrap Table with Custom CSS
HTML — Bootstrap table variants
<!-- Table-level colour variants -->
<table class="table table-dark">          <!-- dark theme -->
<table class="table table-success">       <!-- green -->
<table class="table table-striped-columns"> <!-- column stripes -->

<!-- Row-level variants -->
<tr class="table-danger">   <!-- red row -->
<tr class="table-warning">  <!-- amber row -->
<tr class="table-primary">  <!-- blue highlight -->

<!-- Custom CSS overrides -->
<style>
  .table thead th {
    background: #6f42c1;
    color: #fff;
    border-bottom: 2px solid #5a32a3;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
  }
  .table thead th:hover {
    background: #5a32a3;
  }
  .table tbody tr:hover td {
    background-color: rgba(111, 66, 193, 0.06);
  }
  .table-responsive {
    border-radius: 8px;
    box-shadow: 0 2px 12px rgba(0,0,0,.08);
  }
</style>
All Bootstrap 5 table CSS classes
Table classes:  table  table-sm  table-bordered  table-borderless
               table-striped  table-striped-columns  table-hover
               table-dark  table-light  table-responsive{-sm/-md/-lg/-xl}

Color variants: table-primary  table-secondary  table-success
               table-danger   table-warning    table-info
               table-light    table-dark

thead classes:  thead-dark  (use table-dark on thead instead in BS5)
               table-group-divider  (thick border above thead)

Responsive Table on Mobile Devices

The table-responsive wrapper handles the most common mobile problem — horizontal overflow — but there are more advanced patterns for a truly great bootstrap responsive table mobile experience.

12-column financial table on a 375px screen

A finance dashboard table with 12 columns looks fine on a 1440px monitor but is completely unusable on a phone. Three strategies exist: horizontal scroll (fastest), column hiding (shows priority columns), or card transformation (most readable on mobile).
StrategyImplementationAll data visibleEffort
Horizontal scroll.table-responsiveYes (scroll)Zero
Hide columns.d-none .d-md-table-cellPartialLow
Card layoutCSS + media query transformYes (stacked)High

Hide low-priority columns on small screens

HTML — responsive column visibility
<table class="table">
  <thead>
    <tr>
      <th>Name</th>                           <!-- always visible -->
      <th>Status</th>                         <!-- always visible -->
      <th class="d-none d-sm-table-cell">Role</th>       <!-- 576px+ -->
      <th class="d-none d-md-table-cell">Department</th> <!-- 768px+ -->
      <th class="d-none d-lg-table-cell">Salary</th>     <!-- 992px+ -->
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice Chen</td>
      <td><span class="badge bg-success">Active</span></td>
      <td class="d-none d-sm-table-cell">Engineer</td>
      <td class="d-none d-md-table-cell">Backend</td>
      <td class="d-none d-lg-table-cell">$110,000</td>
    </tr>
  </tbody>
</table>

Bootstrap 5 display utility classes for table cells

d-none d-sm-table-cell hides a cell below 576px. d-none d-md-table-cell hides below 768px. Apply the same classes to both <th> and <td> to keep columns aligned.

Conclusion

Use caseRecommended approachExample in this guide
Simple bootstrap table exampleBootstrap classes onlyExample 1
Bootstrap 5 table responsive.table-responsive wrapperExample 2
Bootstrap table search
Vanilla JS input filter
Example 3
Bootstrap table sortingClick handler + array sortExample 4
Bootstrap table paginationTablePaginator classExample 5
Bootstrap table pagination search sortingBootstrapDataTable classExample 6
Quick plugin-based bootstrap data table
bootstrap-table.js
Example 7
Custom bootstrap responsive table mobileColumn hiding utilitiesExample 8

Building a responsive Bootstrap table with pagination, search and sorting in Bootstrap 5 requires no external libraries — just Bootstrap’s CSS classes and ~150 lines of vanilla JavaScript. The BootstrapDataTable class from Example 6 is the foundation you can take directly into production: copy it, add your own data source (fetch from an API or populate from a server-rendered page), and extend with custom sort functions for date columns or badge columns.

If you need server-side bootstrap table pagination — where the server returns only one page of data at a time — wire the page and search state to API query parameters and replace the render() method with a fetch() call. The architecture is identical; only the data source changes. For very complex requirements (Excel export, frozen columns, tree rows), reach for bootstrap-table.js or DataTables — but for the vast majority of bootstrap table with search and sorting example needs, vanilla JS is more than enough.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x