# How to create a complex search function in Bubble.io: Step-by-Step Guide

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

## TL;DR

Build an advanced multi-filter search in Bubble that combines text input, dropdown filters, date range selectors, and sorting options to query a single Repeating Group in real time. This tutorial walks through setting up compound search constraints that update results instantly as users adjust any filter.

## Overview: Building a Complex Search in Bubble

Simple keyword search is often not enough. Users need to filter by category, status, date range, and then sort the results. This tutorial shows how to build a single search interface that combines all these filters into one query on a Repeating Group, updating results in real time without requiring a search button.

## Before you start

- A Bubble app with at least one Data Type containing 10+ records
- Basic understanding of Repeating Groups and Do a search for
- Familiarity with the Design and Workflow tabs

## Step-by-step guide

### 1. Set up the filter UI elements

On your search page in the Design tab, add a Row group at the top. Inside it, place a Search Input for text search, a Dropdown for category (data source: your category Option Set), a Dropdown for status filter, two Date Picker elements for start and end date, and a Dropdown for sort order with options like Newest First, Oldest First, A-Z, and Z-A. Arrange them in a single row with appropriate spacing.

**Expected result:** A filter bar with text search, category dropdown, status dropdown, date range pickers, and sort dropdown.

### 2. Configure the Repeating Group with compound constraints

Below the filter bar, add a Repeating Group. Set its Type of content to your Data Type. Set the data source to Do a search for with these constraints: title contains Search Input's value (check Ignore empty constraints), category equals Dropdown Category's value (check Ignore empty constraints), status equals Dropdown Status's value (check Ignore empty constraints), Created Date is greater than or equal to Date Picker Start's value (check Ignore empty constraints), Created Date is less than or equal to Date Picker End's value (check Ignore empty constraints).

> Pro tip: Always check Ignore empty constraints on every filter constraint. When a filter is empty, that constraint is skipped and all matching records are returned.

**Expected result:** The Repeating Group displays records that match all active filters and shows everything when all filters are empty.

### 3. Add dynamic sorting with conditional data sources

You cannot dynamically change sort order on a single data source. Instead, use conditional data sources on the Repeating Group. Add a conditional: When Dropdown Sort's value is Newest First, set data source to the same search sorted by Created Date descending. When Oldest First, sort by Created Date ascending. When A-Z, sort by title ascending. Each conditional uses the same search constraints but different Sort by values.

**Expected result:** Selecting a sort option re-sorts the Repeating Group results without losing the active filters.

### 4. Display results with empty state handling

Inside the Repeating Group cell, display the key fields: title, category, status badge, and date. Add a Text element below the Repeating Group showing No results found with a conditional: This element is visible when the Repeating Group's list count is 0. This gives users feedback when their filters are too narrow.

**Expected result:** Search results display with relevant information and a no-results message appears when filters return zero matches.

### 5. Add a Clear Filters button

Add a Button labeled Clear Filters next to the filter bar. Create a workflow: When Button Clear Filters is clicked, use the Reset relevant inputs action. This resets all inputs on the page to their default empty state. Because Ignore empty constraints is enabled, clearing all filters returns all records.

**Expected result:** Clicking Clear Filters resets all filter inputs and shows all records in the Repeating Group.

### 6. Optimize search performance for large datasets

If your Data Type has thousands of records, avoid using the :filtered operator after the search — it runs client-side and is slow. Keep all filtering in the Do a search for constraints, which run server-side. Limit the Repeating Group to 20 items per page with pagination. For text search across multiple fields, consider creating a search_text field that concatenates title and description.

> Pro tip: For very large datasets (10,000+ records), consider the OmniSearch plugin which connects to Algolia or Typesense for blazing-fast full-text search.

**Expected result:** Search results load quickly even with thousands of records by using server-side constraints and pagination.

## Complete code example

File: `Workflow summary`

```text
COMPLEX SEARCH — WORKFLOW SUMMARY
==================================

PAGE ELEMENTS
  Row: Filter Bar
    - Search Input (text): keyword search
    - Dropdown Category: Option Set or Data Type
    - Dropdown Status: Option Set
    - Date Picker Start: start date filter
    - Date Picker End: end date filter
    - Dropdown Sort: Newest, Oldest, A-Z, Z-A
    - Button: Clear Filters

  Repeating Group: Search Results
    Type: Product (or your Data Type)
    Data source: Do a search for Products
      - title contains Search Input value
        [x] Ignore empty constraints
      - category = Dropdown Category value
        [x] Ignore empty constraints
      - status = Dropdown Status value
        [x] Ignore empty constraints
      - Created Date >= Date Picker Start value
        [x] Ignore empty constraints
      - Created Date <= Date Picker End value
        [x] Ignore empty constraints
      - Sort by: Created Date, descending

  Conditional data sources on RG:
    When Sort = Newest First:
      Same search, Sort by Created Date desc
    When Sort = Oldest First:
      Same search, Sort by Created Date asc
    When Sort = A-Z:
      Same search, Sort by title asc
    When Sort = Z-A:
      Same search, Sort by title desc

  WORKFLOW: Clear Filters
    Trigger: Button Clear Filters clicked
    Step 1: Reset relevant inputs

  PERFORMANCE TIPS
    - All filters use server-side constraints
    - Pagination: 20 items per page
    - No :filtered operator on large datasets
    - Concatenated search_text field for multi-field search
```

## Common mistakes

- **Forgetting to enable Ignore empty constraints** — Without it, an empty dropdown returns zero results because Bubble looks for records where category equals nothing. Fix: Check the Ignore empty constraints checkbox on every optional filter constraint.
- **Using the :filtered operator instead of search constraints** — The :filtered operator runs client-side on every returned record, which is exponentially slower than server-side constraints for large datasets. Fix: Put all filter logic inside Do a search for constraints. Only use :filtered for complex expressions that cannot be expressed as constraints.
- **Not handling the empty results state** — Users see a blank area and do not know if the search is loading or returned no results. Fix: Add a No results found text element with a visibility condition based on the Repeating Group list count being 0.

## Best practices

- Always enable Ignore empty constraints on optional filter parameters
- Use server-side search constraints rather than client-side :filtered for performance
- Paginate Repeating Groups to 20 items to reduce initial load time
- Create a concatenated search_text field for searching across multiple fields efficiently
- Show a result count above the Repeating Group so users know how many matches exist
- Add a loading indicator that shows while search results are being fetched
- Use Option Sets for filter dropdowns to ensure consistent values

## Frequently asked questions

### Why do my search results disappear when I select a filter?

You likely forgot to check Ignore empty constraints on one of your other filter constraints. When any non-ignored constraint has an empty value, it returns zero results.

### Can I search across multiple fields like title and description?

Yes. Create a search_text field on your Data Type that concatenates title and description. Then search against search_text contains instead of individual fields.

### How do I make search case-insensitive?

Bubble's text contains constraint is already case-insensitive by default. Searching for 'apple' will match 'Apple', 'APPLE', and 'apple'.

### What if I need full-text search with relevance ranking?

Bubble's native search is constraint-based, not relevance-ranked. For full-text search with ranking, use the OmniSearch plugin which connects to Algolia or Typesense.

### Can I save user filter preferences?

Yes. Store the filter values in a custom state or URL parameters. For persistent preferences, save them as fields on the User data type and load them when the page opens.

### Can RapidDev help optimize my search for a large database?

Yes. RapidDev can architect high-performance search systems in Bubble, including external search integration, query optimization, and caching strategies for databases with tens of thousands of records.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/create-a-complex-search-function-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/create-a-complex-search-function-in-bubble
