Build a predictive text input using a Custom Widget that wraps Flutter's Autocomplete widget around a TextField. As the user types, a debounced query (300ms delay) searches a Firestore search_terms collection using prefix matching with the Unicode range trick. Suggestions display in an overlay list below the input. Tapping a suggestion fills the TextField and triggers a search action. For AI-powered predictions, call an OpenAI or Google API with the partial input to generate contextual completions. Debouncing prevents excessive queries on every keystroke.
Building Predictive Text Input with Autocomplete in FlutterFlow
Predictive text helps users find what they need faster by showing suggestions as they type. This tutorial builds an autocomplete input using a Custom Widget with Flutter's Autocomplete widget, Firestore prefix queries for fast matching, and debouncing to control query volume. Optionally, integrate an AI API for context-aware completions.
Prerequisites
- A FlutterFlow project with Firestore configured
- A collection of searchable items (products, users, or search terms) in Firestore
- Basic familiarity with FlutterFlow Custom Widgets and Action Callbacks
Step-by-step guide
Set up the Firestore search terms collection for prefix matching
Set up the Firestore search terms collection for prefix matching
Create a search_terms collection with fields: term (String, lowercase), displayText (String, original casing), category (String, optional), popularity (Integer, for sorting). Populate it with common search terms from your app domain. For product search, you might also query the products collection directly by name. The key for prefix matching is the Unicode range trick: query where term >= userInput AND term < userInput + '\uf8ff'. The character \uf8ff is the highest Unicode code point, so this range captures all strings starting with the user's input.
Expected result: A search_terms collection with lowercase terms ready for prefix matching queries.
Create the Autocomplete Custom Widget with debounced input
Create the Autocomplete Custom Widget with debounced input
Create a Custom Widget PredictiveInput that wraps Flutter's RawAutocomplete widget. Accept a callback parameter onSelected (String). Inside, use a TextField as the field builder and an OverlayEntry as the options builder. Add a debounce Timer: on every text change, cancel the previous timer and start a new 300ms timer. When the timer fires, call the Firestore query with the current input. Display matching results in a Material-elevated ListView overlay positioned below the TextField. On tap, call onSelected with the selected term and close the overlay.
1// Custom Widget: PredictiveInput2import 'dart:async';3import 'package:cloud_firestore/cloud_firestore.dart';45class PredictiveInput extends StatefulWidget {6 final Function(String) onSelected;7 const PredictiveInput({required this.onSelected});89 @override10 State<PredictiveInput> createState() => _PredictiveInputState();11}1213class _PredictiveInputState extends State<PredictiveInput> {14 final _controller = TextEditingController();15 Timer? _debounce;16 List<String> _suggestions = [];1718 void _onChanged(String value) {19 _debounce?.cancel();20 _debounce = Timer(const Duration(milliseconds: 300), () {21 if (value.length < 2) {22 setState(() => _suggestions = []);23 return;24 }25 final lower = value.toLowerCase();26 FirebaseFirestore.instance27 .collection('search_terms')28 .where('term', isGreaterThanOrEqualTo: lower)29 .where('term', isLessThan: '$lower\uf8ff')30 .orderBy('term')31 .limit(8)32 .get()33 .then((snap) {34 setState(() {35 _suggestions = snap.docs36 .map((d) => d['displayText'] as String)37 .toList();38 });39 });40 });41 }4243 @override44 Widget build(BuildContext context) {45 return Column(children: [46 TextField(47 controller: _controller,48 onChanged: _onChanged,49 decoration: InputDecoration(50 hintText: 'Search...',51 prefixIcon: Icon(Icons.search),52 ),53 ),54 if (_suggestions.isNotEmpty)55 Material(56 elevation: 4,57 child: ListView.builder(58 shrinkWrap: true,59 itemCount: _suggestions.length,60 itemBuilder: (_, i) => ListTile(61 title: Text(_suggestions[i]),62 onTap: () {63 _controller.text = _suggestions[i];64 setState(() => _suggestions = []);65 widget.onSelected(_suggestions[i]);66 },67 ),68 ),69 ),70 ]);71 }72}Expected result: A Custom Widget that shows live suggestions in a dropdown as the user types, with 300ms debounce.
Integrate the Custom Widget into your search page
Integrate the Custom Widget into your search page
On your SearchPage, add the PredictiveInput Custom Widget where you want the search bar. Connect the onSelected callback to a FlutterFlow Action Flow: when a suggestion is selected, navigate to the search results page or product detail page with the selected term as a Route Parameter. Below the PredictiveInput, optionally show a 'Recent Searches' ListView from a user-specific recent_searches subcollection and a 'Popular Searches' section from search_terms ordered by popularity descending.
Expected result: The predictive input is live on the search page, with suggestions appearing as users type and navigation on selection.
Add AI-powered predictive completions via API call
Add AI-powered predictive completions via API call
For smarter predictions beyond prefix matching, add an API Call to OpenAI or Google Gemini. In the debounce handler of the Custom Widget, after the Firestore query returns, also call a Cloud Function that sends the partial input to the AI API with a prompt like 'Suggest 5 completions for a user searching for: [input] in a [your domain] app'. Parse the JSON response and merge AI suggestions with Firestore results, deduplicating by term. Display AI-generated suggestions with a sparkle icon to differentiate them. This hybrid approach gives fast Firestore results plus creative AI completions.
Expected result: Users see both database matches and AI-generated suggestions, combining speed with intelligence.
Track search analytics and improve suggestions over time
Track search analytics and improve suggestions over time
When a user selects a suggestion or submits a search, create a search_analytics document with: query (String), selectedSuggestion (String, nullable), userId (String), timestamp (Timestamp). Increment the popularity field on the matching search_terms document using FieldValue.increment(1). Add a scheduled Cloud Function that runs weekly to analyze search_analytics: find frequently searched terms that do not exist in search_terms and auto-create them. This creates a self-improving suggestion system that learns from user behavior.
Expected result: Search suggestions improve over time as popular terms are tracked and new terms are automatically added.
Complete working example
1FIRESTORE DATA MODEL:2 search_terms/{docId}3 term: String (lowercase)4 displayText: String (original casing)5 category: String (optional)6 popularity: Integer78 search_analytics/{docId}9 query: String10 selectedSuggestion: String (nullable)11 userId: String12 timestamp: Timestamp1314PREFIX MATCHING QUERY:15 search_terms16 .where('term', '>=', userInput.toLowerCase())17 .where('term', '<', userInput.toLowerCase() + '\uf8ff')18 .orderBy('term')19 .limit(8)2021DEBOUNCE LOGIC:22 On text change:23 1. Cancel previous timer24 2. Start new 300ms timer25 3. On timer fire: execute Firestore prefix query26 4. Display results in overlay ListView2728CUSTOM WIDGET: PredictiveInput29 Column30 ├── TextField (search icon prefix, onChanged → debounce)31 └── Material (elevation 4, conditional)32 └── ListView.builder (suggestions)33 └── ListTile (displayText)34 On Tap:35 1. Fill TextField36 2. Clear suggestions37 3. Callback: onSelected(term)3839SEARCH PAGE:40 Column41 ├── PredictiveInput Custom Widget42 │ onSelected → Navigate to results page43 ├── Text ("Recent Searches")44 ├── ListView (user's recent_searches)45 ├── Text ("Popular Searches")46 └── ListView (search_terms, order by popularity desc)4748AI ENHANCEMENT (optional):49 After debounce + Firestore query:50 → Cloud Function → OpenAI API51 → Merge AI suggestions with Firestore results52 → Deduplicate53 → Display AI suggestions with sparkle iconCommon mistakes when building a Predictive Text Input Feature in FlutterFlow
Why it's a problem: Querying Firestore on every keystroke without debouncing
How to avoid: Add a 300ms debounce timer that cancels on each keystroke and only fires the query after 300ms of inactivity. This reduces 5 queries to 1.
Why it's a problem: Case-sensitive prefix matching that misses results
How to avoid: Store a lowercase version of each term and convert user input to lowercase before querying. Display the original-casing displayText in the suggestions.
Why it's a problem: Not limiting the number of suggestions returned
How to avoid: Limit the Firestore query to 8-10 results. For the overlay, 5-8 visible suggestions is the optimal user experience.
Best practices
- Debounce input by 300ms to reduce Firestore query volume without hurting responsiveness
- Store terms in lowercase for case-insensitive prefix matching
- Limit suggestion results to 8-10 for optimal user experience and performance
- Require a minimum input length (2 characters) before querying to avoid overly broad matches
- Track search analytics to continuously improve suggestion quality
- Cache AI-generated suggestions for common prefixes to reduce API costs
- Show recent and popular searches when the input is empty for quick access
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a predictive text input in FlutterFlow. Show me how to create a Custom Widget with debounced TextField, Firestore prefix matching using the Unicode range trick, an overlay suggestion list, and optional AI-powered completions via an API call.
Create a search page with a text field at the top and a dropdown list of suggestions that appears below the text field as the user types.
Frequently asked questions
Can I use this for product search in an e-commerce app?
Yes. Instead of a separate search_terms collection, query your products collection directly using the name field with prefix matching. Add category and price range filters alongside the text search for more targeted results.
How do I handle search terms with special characters?
Strip or escape special characters from both the stored terms and user input before querying. Use a sanitization function that removes punctuation and extra spaces for consistent matching.
Can I highlight the matching portion of each suggestion?
Yes. In the ListTile builder, split the suggestion text at the matching prefix. Render the matching portion in bold using a RichText widget with a TextSpan, and the remainder in normal weight.
How many search terms can Firestore handle efficiently?
Firestore handles millions of documents efficiently with the prefix query pattern. The query uses the index directly, so performance is constant regardless of collection size. The 8-item limit on results keeps reads minimal.
Can I add fuzzy matching for misspelled queries?
Firestore prefix matching does not support fuzzy search natively. For fuzzy matching, use a Cloud Function that computes Levenshtein distance on a cached term list, or integrate Algolia or Typesense as a dedicated search backend.
Can RapidDev help build an advanced search system?
Yes. RapidDev can implement full-text search with fuzzy matching, faceted filters, search analytics dashboards, AI-powered suggestions, and integration with dedicated search engines like Algolia.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation