Bubble does not have a native table element, but you can build responsive data tables using Repeating Groups styled as rows with a fixed header Group above. This tutorial covers creating the table layout with column headers, adding sort functionality by clicking headers, enabling horizontal scroll for mobile, and implementing inline editing so users can update records directly in the table.
Overview: Responsive Data Tables in Bubble
This tutorial teaches you how to display database records in a professional table format. You will create a structured layout with column headers and data rows, add sorting and pagination, and make it mobile-friendly with horizontal scroll. The approach uses Bubble's native Repeating Group element.
Prerequisites
- A Bubble app with a Data Type containing records to display
- Basic understanding of Repeating Groups and data sources
- Familiarity with Bubble's responsive layout system
- Understanding of custom states for interactivity
Step-by-step guide
Create the table header row
Create the table header row
In the Design tab, add a Group element set to Row layout. This will be your header row. Inside it, add Text elements for each column header — for example, Name, Email, Date Joined, and Status. Set each text element to a fixed width that matches the column widths you want. Style the header Group with a background color to distinguish it from data rows. Make each header text bold. Set the Group's width to a fixed value wider than the page if you need more columns — this enables horizontal scrolling.
Expected result: A styled header row displays column labels above where the data rows will appear.
Build the data rows with a Repeating Group
Build the data rows with a Repeating Group
Below the header, add a Repeating Group with its type set to your Data Type. Set the layout to Row in a column with a fixed number of rows (10-20 for pagination). Inside the first cell, create a Row group matching the header layout. Add Text elements for each column, binding them to the current cell's data fields. Match each column's width exactly to the corresponding header column. Add alternating row colors using a conditional on the Repeating Group cell: When current cell's index is odd → background color is slightly different.
Expected result: Data records display in aligned rows beneath the header, with each column's data matching its header label.
Add sortable column headers
Add sortable column headers
Create two custom states on the page: 'sort_field' (type text) and 'sort_direction' (type text, default 'ascending'). Make each header text clickable by adding a workflow to each one. When a header is clicked, set sort_field to that column name and toggle sort_direction between ascending and descending. Update the Repeating Group's data source to use Dynamic sorting — set Sort by to a dynamic value based on sort_field and Sort order based on sort_direction. Add a small arrow icon next to each header that changes direction based on the current sort state.
Pro tip: Bubble's Do a Search For supports :sorted operator which lets you sort by any field dynamically. Combine this with your custom state for the sort field.
Expected result: Clicking a column header sorts the table by that column, and clicking again reverses the sort order.
Enable horizontal scroll for mobile
Enable horizontal scroll for mobile
Wrap both the header Group and the Repeating Group inside a parent Group. Set this parent Group's width to match the total table width. Then wrap that Group inside another outer Group that has a fixed width matching the page and 'Allow horizontal scrolling when content overflows' enabled. On mobile breakpoints, the outer container stays within screen bounds while the inner table extends beyond it, allowing users to scroll horizontally to see all columns. Test this by resizing your browser to mobile width.
Expected result: On mobile screens, the table scrolls horizontally to reveal all columns while the page layout stays intact.
Implement inline cell editing
Implement inline cell editing
For editable columns, replace the Text element in the Repeating Group cell with an Input element. Set the Input's initial content to the current cell's field value. Set the Input to appear as plain text by default using conditional formatting — remove borders and background when it is not focused. Add a workflow: When the Input's value is changed and the Input is not focused → Make changes to Current cell's data type, setting the field to the Input's value. This auto-saves changes when the user clicks away from the cell.
Pro tip: Add visual feedback when a cell is being edited — show a subtle border or highlight color when the Input is focused so users know they are in edit mode.
Expected result: Users can click on a table cell, edit the value inline, and the change saves automatically when they click away.
Complete working example
1RESPONSIVE TABLE SETUP SUMMARY2=====================================34HEADER ROW:5 Group (Row layout, background color)6 → Text: Name (width: 200px, bold)7 → Text: Email (width: 250px, bold)8 → Text: Date Joined (width: 150px, bold)9 → Text: Status (width: 120px, bold)1011DATA ROWS:12 Repeating Group (type: [Data Type])13 Layout: Column, fixed rows: 1514 Data source: Do a Search sorted by sort_field15 Cell → Group (Row layout)16 → Text/Input: Name (200px)17 → Text/Input: Email (250px)18 → Text: Date (150px, formatted)19 → Text: Status (120px)20 Conditional: odd index → alt background2122SORTING:23 Custom states on page:24 sort_field (text, default: 'Created Date')25 sort_direction (text, default: 'descending')26 Header click workflow:27 Set sort_field = column name28 Toggle sort_direction29 RG data source: sorted by sort_field30 Arrow icon: conditional on sort_direction3132HORIZONTAL SCROLL:33 Outer Group: page width, overflow scroll34 Inner Group: total table width (720px+)35 Header Group36 Repeating Group3738INLINE EDITING:39 Replace Text with Input in editable cells40 Input initial content = current cell's field41 Conditional: not focused → no border42 Workflow: value changed + not focused43 → Make changes to current cell's thing44 → Set field = Input's value4546PAGINATION:47 Custom state: current_page (number)48 Next/Previous buttons49 RG offset = (current_page - 1) * rows_per_pageCommon mistakes when building Responsive Data Tables in Bubble
Why it's a problem: Not matching column widths between the header and data rows
How to avoid: Set explicit fixed widths on both header texts and corresponding data cell elements, ensuring they match exactly
Why it's a problem: Using a full-width table on mobile without horizontal scroll
How to avoid: Wrap the table in a container with horizontal scroll enabled so mobile users can swipe to see all columns
Why it's a problem: Running searches inside repeating group cells for computed columns
How to avoid: Pre-compute values as fields on the Data Type or use parent group references
Best practices
- Use fixed column widths to maintain alignment between headers and data rows
- Paginate to 10-20 rows for optimal performance and usability
- Add alternating row colors for better readability
- Implement horizontal scroll for tables wider than mobile screens
- Show sort direction indicators on column headers for clear UX
- Use inline editing only for fields users frequently update
- Add a loading indicator while data is being fetched
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I need to display a database of 500 users in a table format in my Bubble.io app with sortable columns and pagination. How do I build this with a Repeating Group?
Help me build a data table showing customer orders with columns for order number, customer name, date, total, and status. I want sortable headers and inline status editing.
Frequently asked questions
Does Bubble have a built-in table element?
No. Bubble does not have a native table element. Tables are built using Repeating Groups styled as rows with a header Group above for column labels.
How many columns can a Bubble table have?
There is no hard limit on columns. However, more than 8-10 columns may require horizontal scrolling on desktop and becomes less user-friendly. Consider which columns are essential for your use case.
Can I export the table data to CSV?
Yes. Add an export button that uses a CSV plugin to generate a downloadable file from the same data source as your Repeating Group.
How do I add a search or filter above the table?
Add an Input element above the table and use its value as a constraint in the Repeating Group's data source. Filter by text contains on the relevant field.
Is inline editing secure?
Inline editing triggers Make changes to a thing, which is subject to Privacy Rules. Ensure your Privacy Rules allow editing only for authorized users.
Can RapidDev help build complex data tables?
Yes. RapidDev can create advanced data table interfaces with multi-column sorting, advanced filtering, inline editing, and bulk actions for your Bubble application.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation