This tutorial shows you how to display a search bar in a Flutter application.
If your application has search functionality, usually you need to include a search input component. You can add a search bar where the users can input search queries. In many cases, it may have some icons before or after the input field. If you develop the application using Flutter, adding a search bar should be quite easy as Flutter provides a built-in widget for it. The SearchBar
widget makes it easy to add a Material Design search bar and customize the appearance. Below are the examples.
This tutorial only explains about the SearchBar
widget which doesn't show a suggestion list. If you have a requirement to show a suggestion list (also referred to as a search view), Flutter has another widget called SearchAnchor
which is suitable for that purpose. However, it's quite common to have a SearchBar
that's turned into a SearchAnchor
when tapped. Therefore, you can read this tutorial if you want to know how to use and customize the widget.
Using SearchBar
Below is the constructor of SearchBar
. It has a lot of named parameters which allow you to customize the colors, leading and trailing icons, and much more.
SearchBar({
Key? key,
TextEditingController? controller,
FocusNode? focusNode,
String? hintText,
Widget? leading,
Iterable? trailing,
GestureTapCallback? onTap,
ValueChanged? onChanged,
BoxConstraints? constraints,
MaterialStateProperty? elevation,
MaterialStateProperty? backgroundColor,
MaterialStateProperty? shadowColor,
MaterialStateProperty? surfaceTintColor,
MaterialStateProperty? overlayColor,
MaterialStateProperty? side,
MaterialStateProperty? shape,
MaterialStateProperty? padding,
MaterialStateProperty? textStyle,
MaterialStateProperty? hintStyle
})
Basic Usage
Since there is no required argument, you can call the constructor without any argument. The result is a basic search bar which doesn't have any icon and uses the default styles.
SearchBar()
Output:
Set Leading Widget
You can add a widget before the input field by passing it as the leading
argument. Typically, it's an icon which means you can use an Icon
or an IconButton
widget. The most common icon to use is the search icon.
SearchBar(
leading: const Icon(Icons.search),
// other arguments
)
Output:
Set Trailing Widgets
You can also add some widgets after the input field by passing a list of widgets as the trailing
argument. Usually, it's used for adding icons of additional actions such as voice search or image search.
SearchBar(
trailing: [
IconButton(
icon: const Icon(Icons.keyboard_voice),
onPressed: () {
print('Use voice command');
},
),
IconButton(
icon: const Icon(Icons.camera_alt),
onPressed: () {
print('Use image search');
},
),
],
// other arguments
)
Output:
Set Background Color
The background color of the search bar can be set by using the backgroundColor
argument. For the argument, the passed value is a MaterialStateProperty
which returns a Color?
value. The default value is obtained from SearchBarThemeData.backgroundColor
. If the theme's value is null, then ColorScheme.surface
will be used as the default value.
SearchBar(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 238, 228, 182)
),
// other arguments
)
Output:
Set Shadow Color
The shadow color surrounding the search bar can be set by using the shadowColor
argument. The type is also a MaterialStateProperty
that returns a Color?
value. SearchBarThemeData.shadowColor
is used as the default value, which fallbacks to ColorScheme.shadow
if the theme doesn't have that value.
SearchBar(
shadowColor: MaterialStateProperty.all(Colors.pinkAccent),
// other arguments
)
Output:
Set Overlay Color
To highlight that the search bar is focused, hovered, or pressed, you can set a custom color passed as the overlayColor
argument. The value is also a MaterialStateProperty
returning a Color?
value.
SearchBar(
overlayColor: MaterialStateProperty.all(Colors.pinkAccent),
// other arguments
)
Output:
Set Elevation
The elevation
argument can be used to set the elevation of the widget. The value for the argument is a MaterialStateProperty
that returns a double?
value. If you don't pass it, Flutter will use SearchBarThemeData.elevation
as the default value. If that's also null, the default value is 6.0
SearchBar(
elevation: MaterialStateProperty.all(20.0),
// other arguments
)
Output:
Set Constraints
For setting the size of the search bar, you can add a BoxConstraints
passed as the constraints
argument. Flutter uses SearchBarThemeData.constraints
as the default value and it falls back to the following value if the theme doesn't have the constraints.
const BoxConstraints(minWidth: 360.0, maxWidth: 800.0, minHeight: 56.0)
Example:
SearchBar(
constraints: const BoxConstraints(
maxWidth: 300,
),
// other arguments
)
Output:
Set Shape
You can customize the shape of the search bar by using the shape
argument. The value passed to the argument is a MaterialStateProperty
that returns an OutlinedBorder?
. The value defaults to SearchBarThemeData.shape
, or StadiumBorder
if the theme's value is null. In the example below, the shape is changed to a rounded square.
SearchBar(
shape: MaterialStateProperty.all(const ContinuousRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
)),
// other arguments
)
Output:
Set Outline
The border of the widget can be set by passing a BorderSide
value as the side
argument. If the argument is not passed, Flutter will use the value of SearchBarThemeData.side
if it's not null or render it without outline otherwise. Actually it's possible to set the outline by defining an OutlinedBorder
with a BorderSide
. However, it will be replaced by the outline passed as the side
argument of the SearchBar
constructor.
SearchBar(
side: MaterialStateProperty.all(const BorderSide(color: Colors.pinkAccent)),
// other arguments
)
Output:
Set Text Style
The style of text inputted by the user can be set by using the textStyle
argument for which you have to pass a MaterialStateProperty
that returns a TextStyle?
.
SearchBar(
textStyle: MaterialStateProperty.all(
const TextStyle(color: Colors.teal, fontWeight: FontWeight.bold)
),
// other arguments
)
Output:
Set Hint Text
To give a hint to the user about what value should be typed on the search bar, you can add a text passed as the hintText
argument. The text style for the hint text can be set by using the hintStyle
argument.
SearchBar(
hintText: 'Type keyword',
hintStyle: MaterialStateProperty.all(const TextStyle(color: Colors.grey)),
// other arguments
)
Output:
Set TextEditingController
If you need to get the text inputted on the search bar, you can pass a TextEditingController
. First, create the controller instance.
final TextEditingController _textEditingController = TextEditingController();
Then, pass it as the controller
argument.
SearchBar(
controller: _textEditingController,
// other arguments
)
Handle Value Changes
Every time the user types and the value changes, you can detect the events and get the current text. It can be done by passing a function as the onChanged
argument. The passed function has one parameter whose value is the current text displayed in the search bar.
SearchBar(
onChanged: (String value) {
print('value: $value');
},
// other arguments
)
Handle Taps
To handle events when the user taps on the search bar, create a function and pass it as the onTap
argument. If you use the SearchAnchor
widget for displaying the suggestion list, usually you need to add the code for opening the SearchContoller
's view.
SearchBar(
onTap: () {
print('tapped');
// The code below only works with SearchAnchor
// _searchController.openView();
},
// other arguments
)
Handle Submit
When the user is done editing the text field, you can handle it by passing a function as the onSubmitted
argument.
SearchBar(
onSubmitted: (String value) {
print('value: $value');
},
// other arguments
)
Set SearchBarThemeData
If you want to set a theme to be applied to all SearchBar
s in the application, you can create a SearchBarThemeData
using the constructor below.
const SearchBarThemeData({
MaterialStateProperty<double?>? elevation,
MaterialStateProperty<Color?>? backgroundColor,
MaterialStateProperty<Color?>? shadowColor,
MaterialStateProperty<Color?>? surfaceTintColor,
MaterialStateProperty<Color?>? overlayColor,
MaterialStateProperty<BorderSide?>? side,
MaterialStateProperty<OutlinedBorder?>? shape,
MaterialStateProperty<EdgeInsetsGeometry?>? padding,
MaterialStateProperty<TextStyle?>? textStyle,
MaterialStateProperty<TextStyle?>? hintStyle,
BoxConstraints? constraints,
})
Then, pass it as the searchBarTheme
argument of the ThemeData
that's passed to the MaterialApp
MaterialApp(
title: 'Woolha.com Flutter Tutorial',
theme: ThemeData.light().copyWith(
searchBarTheme: SearchBarThemeData(
backgroundColor: MaterialStateProperty.all(Colors.teal),
),
),
home: const Home(),
)
SearchBar
Parameters
Key? key
: The widget's key, used to control how a widget is replaced with another.TextEditingController? controller
: Controller for the inputted text.FocusNode? focusNode
: The focus node for the widget.String? hintText
: Text that suggests what should be inputted.Widget? leading
: A widget to be displayed before the input field.Iterable<Widget>? trailing
: List of widgets to be displayed after the input field.GestureTapCallback? onTap
: Function to be called when the user taps the widget.ValueChanged<String>? onChanged
: Function to be called when the input changes.BoxConstraints? constraints
: The size constraints.MaterialStateProperty<double?>? elevation
: The elevation of the widget.MaterialStateProperty<Color?>? backgroundColor
: The background color.MaterialStateProperty<Color?>? shadowColor
: The shadow color.MaterialStateProperty<Color?>? surfaceTintColor
: The surface tint color.MaterialStateProperty<Color?>? overlayColor
: The highlight color to indicate the state.MaterialStateProperty<BorderSide?>? side
: The outline of the widget.MaterialStateProperty<OutlinedBorder?>? shape
: The shape of the widget.MaterialStateProperty<EdgeInsetsGeometry?>? padding
: The padding between the search bar's boundary and the contents.MaterialStateProperty<TextStyle?>? textStyle
: The style for the inputted text.MaterialStateProperty<TextStyle?>? hintStyle
: The style for thehintText
.
SearchBarThemeData
Parameters
MaterialStateProperty<double?>? elevation
: The elevation of the widget.MaterialStateProperty<Color?>? backgroundColor
: The background color.MaterialStateProperty<Color?>? shadowColor
: The shadow color.MaterialStateProperty<Color?>? surfaceTintColor
: The surface tint color.MaterialStateProperty<Color?>? overlayColor
: The highlight color to indicate the state.MaterialStateProperty<BorderSide?>? side
: The outline of the widget.MaterialStateProperty<OutlinedBorder?>? shape
: The shape of the widget.MaterialStateProperty<EdgeInsetsGeometry?>? padding
: The padding between the search bar's boundary and the contents.MaterialStateProperty<TextStyle?>? textStyle
: The style for the inputted text.MaterialStateProperty<TextStyle?>? hintStyle
: The style for thehintText
.BoxConstraints? constraints
: The size constraints.
Full Code
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Woolha.com Flutter Tutorial',
theme: ThemeData.light().copyWith(
searchBarTheme: SearchBarThemeData()
),
home: SearchBarExample(),
);
}
}
class SearchBarExample extends StatefulWidget {
const SearchBarExample({super.key});
@override
State<StatefulWidget> createState() {
return _SearchBarExampleState();
}
}
class _SearchBarExampleState extends State<SearchBarExample> {
final SearchController _searchController = SearchController();
final TextEditingController _textEditingController = TextEditingController();
final focusNode = FocusNode();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: SearchBar(
controller: _textEditingController,
elevation: MaterialStateProperty.all(20.0),
constraints: const BoxConstraints(
maxWidth: 300,
),
side: MaterialStateProperty.all(const BorderSide(color: Colors.pinkAccent)),
shape: MaterialStateProperty.all(const ContinuousRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
// side: BorderSide(color: Colors.pinkAccent),
)),
overlayColor: MaterialStateProperty.all(Colors.pinkAccent),
shadowColor: MaterialStateProperty.all(Colors.pinkAccent),
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 238, 228, 182)
),
hintText: 'Type keyword',
hintStyle: MaterialStateProperty.all(const TextStyle(color: Colors.grey)),
textStyle: MaterialStateProperty.all(
const TextStyle(color: Colors.teal, fontWeight: FontWeight.bold)
),
onChanged: (String value) {
print('value: $value');
},
onTap: () {
print('tapped');
// The code below only works with SearchAnchor
// _searchController.openView();
},
leading: const Icon(Icons.search),
trailing: [
IconButton(
icon: const Icon(Icons.keyboard_voice),
onPressed: () {
print('Use voice command');
},
),
IconButton(
icon: const Icon(Icons.camera_alt),
onPressed: () {
print('Use image search');
},
),
],
),
),
),
);
}
@override
void dispose() {
_searchController.dispose();
_textEditingController.dispose();
super.dispose();
}
}
Full Code
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Woolha.com Flutter Tutorial',
theme: ThemeData.light().copyWith(
searchBarTheme: SearchBarThemeData(
backgroundColor: MaterialStateProperty.all(Colors.teal),
)
),
home: Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
body: const Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: SearchBarExample(),
),
),
),
);
}
}
class SearchBarExample extends StatefulWidget {
const SearchBarExample({super.key});
@override
State<StatefulWidget> createState() {
return _SearchBarExampleState();
}
}
class _SearchBarExampleState extends State<SearchBarExample> {
final SearchController _searchController = SearchController();
final TextEditingController _textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return SearchBar(
controller: _textEditingController,
elevation: MaterialStateProperty.all(20.0),
constraints: const BoxConstraints(
maxWidth: 300,
),
side: MaterialStateProperty.all(const BorderSide(color: Colors.pinkAccent)),
shape: MaterialStateProperty.all(const ContinuousRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
// side: BorderSide(color: Colors.pinkAccent),
)),
overlayColor: MaterialStateProperty.all(Colors.pinkAccent),
shadowColor: MaterialStateProperty.all(Colors.pinkAccent),
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 238, 228, 182)
),
hintText: 'Type keyword',
hintStyle: MaterialStateProperty.all(const TextStyle(color: Colors.grey)),
textStyle: MaterialStateProperty.all(
const TextStyle(color: Colors.teal, fontWeight: FontWeight.bold)
),
onChanged: (String value) {
print('value: $value');
},
onTap: () {
print('tapped');
// The code below only works with SearchAnchor
// _searchController.openView();
},
onSubmitted: () {
print('submitted: ${_textEditingController.value.text}');
},
leading: const Icon(Icons.search),
trailing: [
IconButton(
icon: const Icon(Icons.keyboard_voice),
onPressed: () {
print('Use voice command');
},
),
IconButton(
icon: const Icon(Icons.camera_alt),
onPressed: () {
print('Use image search');
},
),
],
);
}
@override
void dispose() {
_searchController.dispose();
_textEditingController.dispose();
super.dispose();
}
}
Summary
For displaying a search bar in a Flutter application, you can use the SearchBar
widget. It has a lot of arguments that allow you to add leading and trailing widgets, customize the shape, set hint text, and much more. If you want to have a search feature with a view for displaying a suggestion list, you should use SearchAnchor
instead. Actually, it's very common to have a SearchBar
as the initial widget of a SearchAnchor
widget.
You can also read about: