Flutter - Using SearchBar Widget Examples

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.

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:

Flutter - SearchBar

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:

Flutter - SearchBar - Leading Widget

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:

Flutter - SearchBar - Trailing Widgets

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:

Flutter - SearchBar - Background Color

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:

Flutter - SearchBar - Shadow Color

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:

Flutter - SearchBar - Overlay Color

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:

Flutter - SearchBar - Elevation

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:

Flutter - SearchBar - Constraints

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:

Flutter - SearchBar - Shape

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:

Flutter - SearchBar - Outline

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:

Flutter - SearchBar - Text Style

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:

Flutter - SearchBar - Hint

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 SearchBars 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 the hintText.

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 the hintText.
  • 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: