global_search_bar 1.0.0
global_search_bar: ^1.0.0 copied to clipboard
A highly customizable, generic search bar package for Flutter supporting network debounce, local filtering, search history, and text highlighting.
Global Search Bar #
A Powerful, Highly Customizable, and Generic Search Bar For Flutter
Global Search Bar provides everything you need to build modern search experiences, including network search, local filtering, debouncing, search history, text highlighting, and full programmatic control all without any external dependencies.
This package utilizes a Headless UI (Render Props) approach. It handles all the heavy lifting (API calls, debouncing, history management, and state tracking) while giving you 100% freedom to design and render your results anywhere on the screen (ListView, GridView, Cards, etc.).
Features #
- Network Search (REST APIs, Firebase, Supabase, etc.)
- Local Search Support
- Built-in Debouncer
- Automatic Query Highlighting (
SearchHighlightText) - Search History Support (with Custom Builders)
- Headless UI Approach (Full control over how results are displayed!)
- Programmatic Control
- Generic Type Support
- Zero External Dependencies
📦 Installation #
Add the package to your project:
dependencies:
global_search_bar: ^1.0.0
Then install packages:
flutter pub get
🚀 Basic Usage #
import 'package:global_search_bar/global_search_bar.dart';
// (1) Declare state variables in your StatefulWidget
bool _isLoading = false;
List<UserModel> _users = [];
// (2) Use the GlobalSearchBar
GlobalSearchBar<UserModel>(
// Delay before calling the API (reduces server load while the user is typing)
debounceDuration: const Duration(milliseconds: 500),
// The actual asynchronous API call or local filtering logic
searchCallback: (query) async {
return await api.searchUsers(query);
},
// Callback fired when the search starts/stops loading
onLoading: (isLoading) {
setState(() => _isLoading = isLoading);
},
// Callback fired when data is successfully fetched
onResults: (results) {
setState(() => _users = results);
},
// Callback fired if searchCallback throws an exception
onError: (error) {
print('Error occurred: $error');
},
)
// (3) Render your results ANYWHERE in your UI!
// Use the included [SearchHighlightText] widget to easily highlight the searched query.
Expanded(
child: ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
final user = _users[index];
return ListTile(
title: SearchHighlightText(
text: user.name, // The original full text
query: _controller.query, // The current text in the search bar
highlightStyle: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue, // The searched letters will be highlighted in blue!
),
),
);
},
),
)
Programmatic Control #
Control the search bar from anywhere using GlobalSearchController
Create Controller #
final controller = GlobalSearchController();
Clear Search #
controller.clear();
Request Focus #
// Opens the keyboard programmatically
controller.focus();
Get Current Query #
// Safely read the current text without managing TextEditingControllers
print(controller.query);
Connect Controller #
GlobalSearchBar<String>(
controller: controller, // Link it to the widget here
)
Search History #
The package manages the search history UI internally.
You only provide how to store and retrieve data.
GlobalSearchBar<String>(
// Must be true to enable local history logic
enableHistory: true,
fetchHistory: () async {
// Load history from local storage when the widget initializes
final prefs = await SharedPreferences.getInstance();
return prefs.getStringList("search_history") ?? [];
},
saveHistory: (query) async {
// Called automatically when the user submits a search.
// Implement your SharedPreferences/Hive saving logic here.
},
historyBuilder: (context, history, onHistoryTap) {
// Renders directly below the search bar when the field is focused and empty.
// You have full control over how the history chips/list look!
return Wrap(
spacing: 8,
children: history.map((term) => ActionChip(
label: Text(term),
// Trigger a new search when a history item is tapped
onPressed: () => onHistoryTap(term),
)).toList(),
);
},
)
Customization #
Almost every part of the widget can be customized.
| Property | Description |
|---|---|
searchCallback |
(Required) Future function that returns a list of type |
onResults |
Callback triggered when results are successfully fetched |
onLoading |
Callback triggered to notify the parent about the loading state |
onError |
Callback triggered if an error occurs during searchCallback |
debounceDuration |
Delay before triggering search (Defaults to 500ms) |
inputDecoration |
Fully customize the TextField (borders, icons, hint text) |
textStyle |
Customize the input text style |
cursorColor |
Change the TextField cursor color |
enableHistory |
Enables or disables local search history behavior |
fetchHistory |
Future function to load history on startup |
saveHistory |
Function triggered when a valid search is submitted |
historyBuilder |
Custom UI builder for the history section |
controller |
Programmatic control (GlobalSearchController) |
Supported Use Cases #
- REST APIs
- Firebase
- Supabase
- Local Lists
- SQLite
- Hive
- SharedPreferences
- Any asynchronous data source
Preview #

+-----------------------------+
| Search Movies : |
+-----------------------------+
BATman Begins
BATman: The Dark Knight
BATman & Robin
Roadmap #
- ✅ Network Search
- ✅ Local Search
- ✅ Debouncer
- ✅ Search Highlight
- ✅ Search History
- ✅ Programmatic Controller
- ✅ Headless UI architecture
- ❌ Animated Suggestions
- ❌ Voice Search
- ❌ Infinite Pagination
- ❌ Search Categories
- ❌ Recent Search Chips
Contributing #
Contributions, issues, and feature requests are welcome.
If you find a bug or have an idea, feel free to open an issue or submit a pull request.
Author #
Ismail Magdy
- GitHub: https://github.com/Ismail-Magdy
- LinkedIn: https://www.linkedin.com/in/ismailmagdy021
📄 License #
This project is licensed under the MIT License.
See the LICENSE file for details.
