What is a search bar?
A search bar is a user interface element that allows the user to enter a search query and submit it to search a database or other information repository. Search bars are commonly used in web browsers, search engines, and app store apps to find specific information or content.
A search bar typically consists of a text field where the user can enter their search query, and a button or icon to submit the query. Some search bars also include additional features, such as autocomplete suggestions, filters, or recent searches.
In Flutter, you can implement a search bar using the TextField
widget with the decoration
attribute set to an InputDecoration
with a hintText
of “Search…” and a search icon or button as the prefixIcon
or suffixIcon
. You can customize the appearance and behaviour of the search bar by changing the properties of the TextField
and the InputDecoration
, as well as by adding additional widgets or callbacks.
Search bar placement
The search bar in Flutter app can be placed in various locations depending on your design and user experience goals. Here are a few common places where you can include a search bar:
- App bar: You can add a search bar to the app bar of your app, as I described in my previous example. This is a convenient location for the search bar because it is always visible at the top of the screen. However, the app bar may not have enough space to display a full-fledged search bar, so you may want to consider using a floating search bar or a search drawer instead.
- Floating search bar: A floating search bar is a search bar that appears on top of the content of the app when the user scrolls down. This allows the user to access the search bar at any time, while also keeping the app bar uncluttered. To implement a floating search bar in Flutter, you can use a
SliverAppBar
widget with afloating
attribute set totrue
. - Search drawer: A search drawer is a full-screen search interface that is accessible from the app bar or a dedicated search button. This design allows the user to expand the search interface when needed while keeping the app bar uncluttered. To implement a search drawer in Flutter, you can use a
Drawer
widget with a search bar as the main content. - Landing page: You can also place a search bar on the landing page of your app, especially if your app’s primary function is search. This allows the user to start searching as soon as they open the app.
- Screen bottom sheet: A screen bottom sheet is a full-screen interface that appears at the bottom of the screen when the user performs a specific action, such as tapping a button or selecting an item from a list. You can use a screen bottom sheet to display a search bar and other search-related elements, such as filters or recent searches. To implement a screen bottom sheet in Flutter, you can use a
BottomSheet
widget. - And more 🙂
Simple Flutter Search Bar
Here is an example of how you could implement a search bar in Flutter:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
textTheme: const TextTheme(
// bodyText2: TextStyle(color: Colors.red, fontWeight: FontWeight.w900),
),
),
home: const MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutterassets.com'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
// Add padding around the search bar
padding: const EdgeInsets.symmetric(horizontal: 8.0),
// Use a Material design search bar
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search...',
// Add a clear button to the search bar
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () => _searchController.clear(),
),
// Add a search icon or button to the search bar
prefixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: () {
// Perform the search here
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
),
),
),
),
);
}
}
This search bar is implemented as a StatefulWidget
because we want to store the value of the search bar in a TextEditingController
. The search bar itself is a TextField
with a hintText
of “Search…” and a clear button as the suffixIcon
. The prefixIcon
is an IconButton
with an Icon
of a search icon. The search bar also has a border with rounded corners.
You can customize this search bar further by changing the appearance and behaviour of the TextField
, such as the keyboardType
or the onChanged
callback. You can also use this search bar as a starting point and build upon it to create a more advanced search interface.
Search icon outside search border
Here is an example of how you can place a search icon outside the border of the search bar:
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
// Add a search icon or button outside the border of the search bar
IconButton(
icon: Icon(Icons.search),
onPressed: () {
// Perform the search here
},
),
Expanded(
// Use a Material design search bar
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search...',
// Add a clear button to the search bar
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () => _searchController.clear(),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
),
),
),
],
),
),
I placed the search icon or button outside the border of the search bar by wrapping the search bar and the search icon or button in a Row
widget and using an Expanded
widget to occupy the remaining space. This allows the search bar to take up most of the available space, while the search icon or button is aligned to the right.
You can customize the appearance and behaviour of the search icon or button by changing the icon
and onPressed
callback, as well as the layout of the Row
widget. You can also adjust the padding and spacing between the search bar and the search icon or button to achieve the desired look and feel.
Search bar in the AppBar in Flutter
You can place a search bar in the app bar in Flutter. Here is an example of how you can do this:
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
appBar: AppBar(
title: Container(
// Add padding around the search bar
padding: const EdgeInsets.symmetric(horizontal: 8.0),
// Use a Material design search bar
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search...',
// Add a clear button to the search bar
suffixIcon: IconButton(
icon: Icon(Icons.clear, color: Colors.black,),
onPressed: () => _searchController.clear(),
),
// Add a search icon or button to the search bar
prefixIcon: IconButton(
icon: Icon(Icons.search, color: Colors.black,),
onPressed: () {
// Perform the search here
},
),
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(20.0),
// ),
),
),
)
),
I added a search bar to the app bar by using a TextField
widget as the title
of the AppBar
. The search bar has a hintText
of “Search…” and a clear button as the suffixIcon
.
You can customize the appearance and behaviour of the search bar by changing the properties of the TextField
, such as the keyboardType
or the onChanged
callback. You can also add a search icon or button to the search bar, as I described in my previous examples.
Keep in mind that the app bar may not have enough space to display a full-fledged search bar, so you may want to consider using a floating search bar or a search drawer instead. These designs allow the user to expand the search interface when needed while keeping the app bar uncluttered.
Floating search bar in Flutter
Here is an example of how you can implement a floating search bar in Flutter:
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
CustomScrollView(
slivers: [
// Add a floating search bar to the app
SliverAppBar(
floating: true,
// Use a Material design search bar
title: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search...',
// Add a clear button to the search bar
suffixIcon: IconButton(
icon: Icon(Icons.clear, color: Colors.black,),
onPressed: () => _searchController.clear(),
),
),
),
),
// Add a list of items to the app
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return ListTile(
title: Text('Item $index'),
);
},
childCount: 20,
),
),
],
),
In this example, I added a floating search bar to the app using a SliverAppBar
widget with the floating
attribute set to true
. The search bar itself is a TextField
with a hintText
of “Search…” and a clear button as the suffixIcon
.
The SliverAppBar
widget is part of the CustomScrollView
widget, which allows the search bar to float on top of the content of the app when the user scrolls down. The CustomScrollView
also includes a SliverList
widget with a list of items, which allows the user to scroll through the content and see the floating search bar.
You can customize the appearance and behaviour of the floating search bar by changing the properties of the TextField
and the SliverAppBar
, as well as by adding additional widgets or callbacks. For example, you can add a search icon or button to the search bar, or use the onChanged
callback of the TextField
to perform a search as the user types.
Sticky search bar in Flutter
Here is an example of a search bar that is always visible in Flutter:
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
final FocusNode _searchFocusNode = FocusNode();
Column(
children: [
// Add the floating search bar
Container(
height: 60,
child: TextField(
focusNode: _searchFocusNode,
controller: _searchController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
hintText: 'Search...',
border: OutlineInputBorder(),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
),
),
],
),
This example creates a Scaffold
with a Column
that contains a search bar and a list of items. The search bar is implemented using a TextField
widget with a prefixIcon
and a hintText
to indicate its purpose and a border
to give it a visual separation from the rest of the screen.
To make the search bar always visible, it is added to the top of the Column
and given a fixed height. The list of items is added below the search bar and given the remaining space using the Expanded
widget.
Create a Search drawer in Flutter
Here is an example of how to create a search drawer in Flutter:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
textTheme: const TextTheme(
// bodyText2: TextStyle(color: Colors.red, fontWeight: FontWeight.w900),
),
),
home: const MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
final FocusNode _searchFocusNode = FocusNode();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutterassets.com'),
),
body: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
),
drawer: SafeArea(
child: Drawer(
child: Column(
children: [
// Add the search bar to the drawer
Container(
height: 60,
child: TextField(
focusNode: _searchFocusNode,
controller: _searchController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
hintText: 'Search...',
border: OutlineInputBorder(),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return ListTile(
title: Text('Drawer Item $index'),
);
},
),
),
],
),
),
),
);
}
}
This example creates a Scaffold
with an app bar, a body, and a drawer. The body contains a list of items, and the drawer contains a search bar and a list of items.
The search bar is implemented using a TextField
widget with a prefixIcon
and a hintText
to indicate its purpose and a border
to give it a visual separation from the rest of the drawer. It is added to the top of the drawer’s Column
and given a fixed height. The list of items is added below the search bar and given the remaining space using the Expanded
widget.
To open and close the drawer, you can use the Drawer
widget’s openEndDrawer
and closeEndDrawer
methods, respectively. You can also use the Scaffold
widget’s drawer
property to toggle the drawer open and closed by tapping on the app bar’s hamburger icon.
Search bar with showModalBottomSheet in Flutter
Here is an example of how to create a search bar in a bottom sheet in Flutter:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
textTheme: const TextTheme(
// bodyText2: TextStyle(color: Colors.red, fontWeight: FontWeight.w900),
),
),
home: const MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
final FocusNode _searchFocusNode = FocusNode();
void initState() {
SystemChannels.textInput.invokeMethod('TextInput.hide');
super.initState();
}
@override
Widget build(BuildContext context) {
// FocusScope.of(context).requestFocus(new FocusNode());
return Scaffold(
appBar: AppBar(
title: const Text('flutterassets.com'),
),
body: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Show the bottom sheet with the search bar
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
height: 60,
child: TextField(
autofocus: false,
focusNode: _searchFocusNode,
controller: _searchController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
hintText: 'Search...',
border: OutlineInputBorder(),
),
),
),
);
},
);
},
child: Icon(Icons.search),
),
);
}
}
This example creates a Scaffold
with a body and a floating action button. The body contains a list of items, and the floating action button opens a bottom sheet with a search bar.
The search bar is implemented using a TextField
widget with a prefixIcon
and a hintText
to indicate its purpose and a border
to give it a visual separation from the rest of the bottom sheet.
To open the bottom sheet, the showModalBottomSheet
function is called and passed a context
and a builder
function that returns the bottom sheet’s content. The bottom sheet can be closed by tapping outside of it or by pressing the device’s back button.
Search bar with FloatingActionButton in Flutter
To create a search bar inside a FloatingActionButton in Flutter, you can use a FloatingActionButton.extended
widget and wrap the search bar inside the label
property of the button.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
textTheme: const TextTheme(
// bodyText2: TextStyle(color: Colors.red, fontWeight: FontWeight.w900),
),
),
home: const MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
bool _isExpanded = false;
void initState() {
SystemChannels.textInput.invokeMethod('TextInput.hide');
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutterassets.com'),
),
body: GestureDetector(
onTap: (){
setState(() {
_isExpanded = !_isExpanded;
});
},
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
),
),
floatingActionButton: _isExpanded
? FloatingActionButton.extended(
onPressed: () {
// Perform search action
setState(() {
_isExpanded = !_isExpanded;
});
},
label: Container(
width: 250,
child: TextField(
controller: _searchController,
decoration: const InputDecoration(
hintText: 'Search...',
border: InputBorder.none,
),
),
),
icon: Icon(Icons.search),
)
: FloatingActionButton(
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
child: Icon(Icons.search),
)
);
}
}
The search bar is implemented using a TextField
widget inside a FloatingActionButton.extended
. The search bar can be expanded and collapsed by pressing the button and the _isExpanded
flag is used to toggle the visibility of the search bar. The _searchController
is used to store the value of the search bar.
The ListView
is wrapped in a GestureDetector
, which allows the user to expand the search bar by tapping anywhere on the screen. When the user taps the screen, the _isExpanded
flag is toggled and the search bar is shown or hidden.
Search bar with AlertDialog in Flutter
To create a search bar with an Alert dialog in Flutter, you can use an AlertDialog
widget and wrap the search bar inside it.
Here’s an example of how you can achieve this:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
textTheme: const TextTheme(
// bodyText2: TextStyle(color: Colors.red, fontWeight: FontWeight.w900),
),
),
home: const MyHomePage(title: 'Flutter Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// This controller will store the value of the search bar
final TextEditingController _searchController = TextEditingController();
void initState() {
SystemChannels.textInput.invokeMethod('TextInput.hide');
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('flutterassets.com'),
),
body: Container(
padding: EdgeInsets.all(12),
child: ElevatedButton(
onPressed: () {
showSearchDialog(context);
},
child: Text('Show search dialog'),
),
),
);
}
void showSearchDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
alignment: Alignment.topCenter,
title: Text('Search'),
content: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Enter search query...',
),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
TextButton(
onPressed: () {
// Perform search action
Navigator.of(context).pop();
},
child: Text('Search'),
),
],
);
},
);
}
}
This will create a button that, when pressed, shows an Alert dialog with a search bar inside it. The search bar will have a text field where the user can enter their search query. The user can then press the “Search” button to perform the search action, or the “Cancel” button to close the dialog.
The _searchController
is used to store the value of the search bar. When the user presses the “Search” button, the onPressed
callback is called, allowing you to perform the search action.