How to search & filter in Bubble.io without complex plugins
As you start building more complex applications in Bubble.io, chances are you'll need to display lists of things (like a directory of products, a list of users, or a product catalog) and empower your users to quickly slice and dice that data to find exactly what they need.
This is where Search and Filtering comes in.
In this post, we're going to tackle a super common scenario: building a dynamic, searchable, and filterable list of "Products" (think of a directory of software, like G2 or Capterra, but built in Bubble). We'll walk through the core concepts using Bubble's powerful built-in features, with no complex plugins needed.
Let's dive in!
Data Structure is key
Before you build any search or filter feature, you have to get your data types right. Think of your database as the foundation. If the foundation is shaky, everything you build on top will be wobbly.
Why is this important? Bubble's search and filtering work by checking the values in fields. If you want to filter by Category, you need a Category field on your Product. If you want to search descriptions, you need a Description field.
For our Product Directory example, let's imagine a Product data type with fields like this:
Field Name | Type |
---|---|
name | text |
company_name | text |
short_description | text |
long_description | text |
has_api | yes/no |
common_use_cases | list of text |
Category | link to a Category data type (e.g., "Project Management", "CRM") |
PrimaryCategory | link to Category (primary category, same type as above) |
Features | list of links to a Feature data type (e.g., "Reporting", "Billing", "Integrations") |
target_user_type | list of Option Sets (e.g., "Small Business", "Enterprise", "Freelancer") |
PricingModel | Option Set (e.g., "Subscription", "One-time", "Free") |
DeploymentType | Option Set (e.g., "Cloud", "On-Premise") |
Integrations | list of links to a Platform data type (e.g., "NetDocuments", "Salesforce") |
Security_Certifications | list of links to a Certification data type (e.g., "ISO 27001", "SOC 2") |
Match_Tags | list of links to a Tag data type (internal matching logic) |
(... and many more fields like price, screenshots, etc.)
Using linked data types (like Category, Feature, Platform) and Option Sets (target_user_type, PricingModel, DeploymentType) is crucial for structured filtering and searching display values efficiently.
Repeating Group for display
Okay, the data structure is sorted. Now, how do we display this list of products? With a Repeating Group.
Think of a Repeating Group like a smart container. You tell it what kind of thing it's going to display (our Product), and then you tell it where to find the list of those things. It will automatically create a cell for each item in that list, and inside each cell, you can design how a single Product item should look (show its name, description, a little badge, etc.).
- Draw a Repeating Group on your page.
- In the property editor, set Type of content to Product.
- Leave the Data source empty for a moment, or set it to Search for Products with no constraints initially. This will show all your products.
- Design one cell of the Repeating Group. Add Text elements for Current cell's Product's name, Current cell's Product's short_description, etc. You can add images, buttons, and anything else here.
Now, you should see a basic list of all your products. Great start.
Add search to make it findable
Users rarely want to see all the data. They want to find something specific via search.
Here’s what we want to do. We want to type a word (like "billing") into a search box, and the Repeating Group updates to show only products relevant to "billing" across their name, description, features, etc.
How do we do this in Bubble? We modify the Data source of our Repeating Group.
- Add an Input element to your page, maybe call it Input Search Products.
- Go back to your Repeating Group's Data source.
- Change or confirm the Data source is Search for Products.
- Now, add Constraints to this Search for Products based on the search input's value. This is where we tell Bubble which products to fetch.
Here's how you'd add constraints based on your requirements:
- name contains Input Search Products's value
- company_name contains Input Search Products's value
- short_description contains Input Search Products's value
- long_description contains Input Search Products's value
- Category's Name contains Input Search Products's value
- Features's Name contains Input Search Products's value
- target_user_type's display contains Input Search Products's value (Search the display text of your Option Set list)
- common_use_cases contains Input Search Products's value (Check if the text list contains the value)
- external_integrations's display contains Input Search Products's value (Search the display text of another Option Set list)
By adding multiple constraints directly to the Search for definition like this, Bubble treats them as "AND". This isn't quite what we want for a broad search (we want products that match in *either* name *or* description *or* features).
For searching across multiple text fields, Bubble offers the Any field contains
operator within constraints. This is a better approach for broad text search. However, this mainly works well on simple text fields.
A common pattern is to use a backend workflow or an "Aggregate" search if performance is an issue with many contains checks. For typical lists, the direct constraints shown above, combined with the Any field contains
operator (if applicable to your text fields), is a good starting point.
Make the search dynamic
To make the search dynamic, you need a workflow.
Create a workflow triggered by "An Input's value is changed" (select your Input Search Products). The action is "Element Actions" -> "Display List" -> Select your Repeating Group. The data source is the same Search for Products expression you built in step 4, referencing the input's value again.
You don't strictly need a separate workflow action for just changing the search input if the Repeating Group's data source already references the input's value. The RG will update automatically when the input changes. So, just setting the RG's data source is enough
Now, as you type in the search box, your Repeating Group should filter in real-time.
Add filters to refine results
Search is great for finding keywords, but filters are perfect for narrowing down by specific categories, types, or features (e.g., "Show me only Project Management products that are Cloud-based and have a Free plan").
Filters work by adding more constraints to that same Search for Products data source on your Repeating Group. Each filter control (dropdown, checkbox, etc.) corresponds to a constraint.
Let's add some filters based on your list:
-
Add filter controls:
- For PrimaryCategory: Add a Dropdown element. Set its "Choices style" to Dynamic choices. Type of choices: Category. Data source: Search for Category. Set the "Option caption" to Current option's Name. Add a blank option for "All Categories".
- For TargetUserTypes: Add a Dropdown (or checkboxes/multi-select). If a dropdown, set Type of choices: target_user_type (your Option Set). Choices source: All target_user_type. Option caption: Current option's display. Add a blank option for "All User Types".
- For PricingModel: Add a Dropdown. Type of choices: PricingModel (your Option Set). Choices source: All PricingModel. Option caption: Current option's display. Add a blank option.
- For DeploymentType: Add a Dropdown. Type of choices: DeploymentType (your Option Set). Choices source: All DeploymentType. Option caption: Current option's display. Add a blank option.
- For Features: Add a Dropdown (or similar). Type of choices: Feature. Choices source: Search for Feature. Option caption: Current option's Name. Add a blank option.
- For has_api: Add a Checkbox. Label it "API Available".
-
Add filter constraints to the Repeating Group's Data Source: Now, go back to your Repeating Group's Search for Products Data source. Add new constraints for each filter:
-
For Category Dropdown: Add constraint Category is Dropdown Category's value.
Check the "ignore empty constraints" box (or ensure the dropdown has a blank option and Bubble handles it). This makes the filter optional. If the dropdown value is empty, this constraint is ignored.
-
For User Type Dropdown: Add constraint target_user_type contains Dropdown User Type's value.
- Why 'contains'? Because the target_user_type field on your Product is likely a list of user types the product serves. You want products where that list contains the single user type selected in the filter.
-
For Pricing Dropdown: Add constraint PricingModel is Dropdown Pricing's value.
-
For Deployment Dropdown: Add constraint DeploymentType is Dropdown Deployment's value.
-
For Features Dropdown: Add constraint Features contains Dropdown Features's value.
- Similar to user types: The Features field on Product is likely a list of features. You want products where that list contains the single feature selected in the filter.
-
For API Checkbox: Add constraint has_api = Checkbox API is checked.
- Handling the unchecked state: You likely only want this constraint active if the checkbox is checked. The easiest way is to add a condition to the constraint itself: Only when Checkbox API is checked is yes. Or, build the search dynamically based on conditions, which is more advanced.
- For simplicity, setting
has_api = Checkbox API is checked
works, as checking the box makes the constrainthas_api = yes
, and unchecking makes ithas_api = no
. If you want the filter off when unchecked, dynamic search construction is needed or conditional on the constraint itself. Let's stick tohas_api = Checkbox API is checked
as a starting point.
-
Your Repeating Group's data source now looks something like Search for Products with all your search and filter constraints applied
. Bubble automatically combines these with AND logic. So, a product must match the search term (in any of the specified fields) AND be in the selected category AND serve the selected user type AND have the selected feature, and so on.
Just like with the search input, when a filter value changes (e.g., a dropdown selection), the Repeating Group's data source updates automatically because it references the filter input's value. No separate workflow is needed to display the list, just workflows if you need to reset filters or perform other actions.
Handling "No Results Found"
What happens if a user's combination of search and filters yields zero results? The Repeating Group will be empty. This is a perfect time to show a helpful message.
-
Add a Text element or a Group containing a message (e.g., "No products match your criteria. Try adjusting your filters.").
-
Make this Text/Group element not visible on page load.
-
Add a Conditional to this Text/Group element:
-
Define another condition
-
This element is visible when -> Repeating Group Products's List of Products:count is 0
-
AND this element is visible when -> Input Search Products's value is not empty OR Dropdown Category's value is not empty OR Checkbox API is checked is yes OR ... (add conditions for each filter input being active)
- Why the second part? You don't want the "No results" message to show when the page first loads before the user has searched or filtered, even if the initial search (on an empty input) returns 0 results for some reason. This condition ensures the message only shows if the list count is zero and the user has tried to filter or search.
-
Reset filters
While much of the dynamic display happens automatically just by setting up the Repeating Group's Data Source correctly, workflows are used for user actions beyond just typing or selecting:
Reset Filters Button: A workflow triggered by clicking a "Reset" button would use "Element Actions" -> "Reset relevant inputs" (targeting your filter dropdowns, checkboxes, etc.) and potentially "Clear" the search input. Since the RG's data source references these inputs, resetting them automatically updates the list back to a broader view.
Conclusion
You've done it! You've built a dynamic, searchable, and filterable list in Bubble. You've learned how to:
- Structure your data effectively using linked types and Option Sets.
- Display lists using the mighty Repeating Group.
- Implement keyword search by adding constraints to the Search for data source.
- Add layered filtering using dropdowns, checkboxes, and other inputs, also via constraints.
- Handle the scenario where no results are found.
- Add visual indicators like badges based on data.
This pattern is fundamental in Bubble and can be applied to lists of anything.
ABOUT ME
I'm Juliet Edjere, a no-code professional focused on automation, product development, and building scalable solutions with no coding knowledge.
I document all things MVP validation and how designs, data, and market trends connect.
Click. Build. Launch.
Visit my website → built with Carrd and designed in Figma