# How to use DataTables plugins in Bubble

- Tool: Bubble
- Difficulty: Beginner
- Time required: 20-25 min
- Compatibility: All Bubble plans
- Last updated: March 2026

## TL;DR

Display database records in a table format in Bubble using Repeating Groups configured as rows and columns. This tutorial covers building a responsive data table with sortable columns, pagination, inline editing, and search filtering so you can present structured data clearly to your users or admin team.

## Overview: Using Data Tables in Bubble

This tutorial shows you how to display database records in a clean table format using Bubble's Repeating Group element. You will build a table with header rows, sortable columns, row pagination, and inline cell editing. This is essential for admin panels, dashboards, and any page that needs to show structured data in rows and columns.

## Before you start

- A Bubble account with a new or existing app
- A Data Type with records to display (this tutorial uses a Product Data Type as an example)
- Basic familiarity with Repeating Groups in Bubble

## Step-by-step guide

### 1. Create the table header row

On your page in the Design tab, add a Row container group at the top of where you want the table. Inside it, add Text elements for each column header: Name, Price, Category, Status, and Actions. Set each text to bold and give the row a light background color like #F3F4F6 to distinguish it from data rows. Set consistent widths for each column by giving each text element a fixed or percentage width.

**Expected result:** A styled header row with column labels appears at the top of your table area.

### 2. Build the data rows with a Repeating Group

Below the header row, add a Repeating Group with Type of content set to your Data Type (such as Product). Set the Data source to Do a Search for Products sorted by Created Date descending. Set the layout to Column with each row being a fixed height of about 48 pixels. Inside each cell, add a Row container. Inside that row, add Text elements matching each header column: Current cell's Product's Name, Current cell's Product's Price formatted as currency, Current cell's Product's Category, and Current cell's Product's Status. Match the widths to the header columns.

> Pro tip: Add alternating row colors using a conditional: when Current cell's index is odd, set the background to white. When even, set it to a very light grey like #F9FAFB.

**Expected result:** A table of data rows appears below the header, with each record displayed in aligned columns matching the header.

### 3. Add sortable column headers

Create a custom state on the page called Sort Field (text, default: Created Date) and another called Sort Order (text, default: descending). On each header Text element, add a click workflow: Set state of page, Sort Field equals the field name (such as Name or Price). In the same workflow, toggle Sort Order between ascending and descending. Update the Repeating Group's data source to use Dynamic sort: Sort Field with direction Sort Order. Add a small arrow icon next to each header that changes direction based on the current sort state.

**Expected result:** Clicking a column header sorts the table by that column. Clicking again reverses the sort direction.

### 4. Implement pagination controls

Set the Repeating Group's number of rows to show to a fixed number like 10 or 20. Below the Repeating Group, add a Row container with pagination controls. Add a Text element showing the current page range (such as Showing 1-10 of 50). Add Previous and Next buttons. For the Next button, create a workflow that increments a custom state called Page Number. Use the Repeating Group's Show next and Show previous actions to navigate between pages. Add an Only when condition to disable Previous on page 1 and Next on the last page.

**Expected result:** The table shows a fixed number of rows per page with Previous and Next buttons to navigate through all records.

### 5. Enable inline editing of table cells

To let users edit data directly in the table, replace one of the Text elements (such as Status) with an Input element. Set its initial content to Current cell's Product's Status. Add a workflow: When Input's value is changed, Make changes to a thing, set Current cell's Product's Status to this Input's value. For a cleaner look, style the Input to look like a Text element (no border, transparent background) and only show a border on focus using the Conditional tab.

> Pro tip: For dropdown selections like Status, use a Dropdown element instead of an Input. Populate it from an Option Set for consistent values.

**Expected result:** Users can click a cell, edit the value, and the change is saved to the database when they click away or press Enter.

### 6. Add a search filter above the table

Above the header row, add a Search Input element. Modify the Repeating Group's data source to include a constraint: Name contains Search Input's value, with Ignore empty constraints checked. This filters the table as the user types. For more advanced filtering, add Dropdown filters for Category and Status with their own constraints on the same search.

**Expected result:** Typing in the search bar filters the table rows in real time. Additional dropdown filters narrow results by category or status.

## Complete code example

File: `Workflow summary`

```text
DATA TABLE — WORKFLOW SUMMARY
==============================

PAGE LAYOUT:
  Search Input + Filter Dropdowns
  Header Row (Row container, bg #F3F4F6):
    Text: Name | Price | Category | Status | Actions
  Repeating Group (Type: Product, Rows: 10)
    Source: Search Products
      Constraints: Name contains Search value
      Sort: [Sort Field] custom state, [Sort Order] custom state
      Ignore empty constraints: checked
  Pagination Row:
    Text: 'Showing X-Y of Z'
    Button: Previous → RG Show previous
    Button: Next → RG Show next

CUSTOM STATES (on page):
  - Sort Field (text, default: 'Created Date')
  - Sort Order (text, default: 'descending')
  - Page Number (number, default: 1)

WORKFLOW 1: Sort Column
  Trigger: Header text clicked
  Actions:
    1. Set state Sort Field = clicked column's field name
    2. Set state Sort Order = toggle asc/desc

WORKFLOW 2: Inline Edit
  Trigger: Input value changed
  Actions:
    1. Make changes to thing → Current cell's Product
       [field] = Input's value

WORKFLOW 3: Next Page
  Trigger: Button Next clicked
  Condition: Page Number < total pages
  Actions:
    1. RG Show next
    2. Set state Page Number + 1

WORKFLOW 4: Previous Page
  Trigger: Button Previous clicked
  Condition: Page Number > 1
  Actions:
    1. RG Show previous
    2. Set state Page Number - 1

STYLING:
  Alternating rows: Conditional on cell index
    Odd → bg white, Even → bg #F9FAFB
  Inline inputs: no border, transparent bg
    On focus → show border
```

## Common mistakes

- **Not matching header column widths to data row widths** — Misaligned columns make the table look broken and hard to read Fix: Use fixed pixel or percentage widths on both header texts and data row elements, ensuring they match exactly
- **Loading all records without pagination** — Loading hundreds or thousands of records at once causes slow page load and high workload unit consumption Fix: Set the Repeating Group to show 10-20 rows and add pagination controls for navigating through the dataset
- **Using client-side filtered operator instead of search constraints for filtering** — The filtered operator downloads all records to the browser before filtering, which is slow and wasteful Fix: Use search constraints (server-side filtering) with the Ignore empty constraints checkbox for efficient data retrieval

## Best practices

- Use fixed column widths on both headers and data cells to maintain alignment
- Paginate large datasets to 10-20 rows per page for performance
- Use search constraints instead of the filtered operator for server-side filtering
- Add alternating row colors for better readability
- Style inline edit inputs to look like text until focused for a clean appearance
- Include a record count display so users know how many total records exist
- Add Privacy Rules to ensure users only see records they are authorized to view

## Frequently asked questions

### Can I export the table data to CSV?

Bubble does not have a native table export feature. You can go to Data tab then App data to export via the built-in CSV export, or use a plugin like CSV Creator to let users export directly from the table.

### How do I handle tables with many columns on mobile?

Hide less important columns on smaller screens using Bubble's responsive breakpoints and conditional visibility. Alternatively, switch to a card layout on mobile where each record is a vertical card instead of a horizontal row.

### Can I add a delete button to each row?

Yes. Add a button or icon in the Actions column of each row. Create a workflow: When delete button is clicked, Delete a thing, thing is Current cell's Product. Add a confirmation popup before deletion to prevent accidents.

### Is there a table plugin for Bubble?

Yes, there are several table plugins on the Bubble marketplace including Table Grid and Data Grid plugins that offer features like column resizing, row selection, and built-in sorting. However, building with Repeating Groups gives you full control over styling and behavior.

### Can RapidDev help build complex admin dashboards?

Yes. RapidDev can help you build sophisticated admin panels with advanced data tables, bulk operations, role-based access, and integrated analytics dashboards.

### How do I sort by multiple columns at once?

Bubble's native sort supports one primary sort field. For multi-column sorting, sort server-side using the primary column in the search constraint, then use the secondary sort as the Sort by parameter. Complex multi-sort may require a Backend Workflow that pre-sorts and caches results.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/use-datatables-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/use-datatables-in-bubble
