image

06 Feb 2026

9K

35K

Creating an Accordion FAQ Widget with Search Filter in Flutter

In modern applications, providing users with quick access to information is crucial for a good user experience. A Frequently Asked Questions (FAQ) section is a common solution, and when combined with an accordion layout and a search filter, it becomes incredibly efficient. This article will guide you through creating a dynamic FAQ accordion widget with a built-in search filter in Flutter.

The widget we'll build will feature:

  • An accordion layout, where users can tap on a question to reveal its answer.
  • A search bar to filter FAQs based on keywords found in both questions and answers.
  • Only one FAQ item can be expanded at a time, providing a clean user interface.

1. Project Setup and FAQ Data Model

First, ensure you have a Flutter project set up. If not, you can create a new one:


flutter create faq_app
cd faq_app

1.1. Defining the FAQ Data Structure

Let's start by defining a simple data model for our FAQ items. Create a file named faq_item.dart inside a lib/models directory.


// lib/models/faq_item.dart
class FaqItem {
  final String question;
  final String answer;

  FaqItem({required this.question, required this.answer});
}

2. Implementing the FAQ Accordion Tile

Next, we'll create a reusable widget for each individual FAQ accordion tile. This widget will display the question and, when expanded, the answer. We'll make it a StatelessWidget, with its expanded state managed by its parent.


// lib/widgets/faq_accordion_tile.dart
import 'package:flutter/material.dart';
import '../models/faq_item.dart';

class FaqAccordionTile extends StatelessWidget {
  final FaqItem faq;
  final bool isExpanded;
  final VoidCallback onTap;

  const FaqAccordionTile({
    Key? key,
    required this.faq,
    required this.isExpanded,
    required this.onTap,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
      child: Column(
        children: [
          ListTile(
            title: Text(
              faq.question,
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
            trailing: Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
            onTap: onTap,
          ),
          if (isExpanded)
            Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 16.0),
              child: Text(faq.answer),
            ),
        ],
      ),
    );
  }
}

3. Building the FAQ Screen with Search Filter

Now, let's put everything together in our main FAQ screen. This screen will contain the search bar, the list of FAQ accordion tiles, and the logic for filtering and expanding/collapsing the tiles.

3.1. Main FAQ Screen Widget

We'll create a StatefulWidget to manage the search text, the filtered list of FAQs, and the currently expanded item's index. Create a file named faq_screen.dart inside a lib/screens directory.


// lib/screens/faq_screen.dart
import 'package:flutter/material.dart';
import '../models/faq_item.dart';
import '../widgets/faq_accordion_tile.dart';

class FaqScreen extends StatefulWidget {
  const FaqScreen({Key? key}) : super(key: key);

  @override
  State createState() => _FaqScreenState();
}

class _FaqScreenState extends State {
  // A static list of all FAQ items
  final List _allFaqs = [
    FaqItem(
      question: 'What is Flutter?',
      answer: 'Flutter is an open-source UI software development kit created by Google. It is used to develop cross-platform applications for Android, iOS, Linux, macOS, Windows, Google Fuchsia, and the web from a single codebase.',
    ),
    FaqItem(
      question: 'How do I install Flutter?',
      answer: 'You can install Flutter by downloading the SDK from the official Flutter website, extracting it, and adding the flutter/bin directory to your PATH environment variable. Then, run `flutter doctor` to check for dependencies.',
    ),
    FaqItem(
      question: 'What is a widget?',
      answer: 'In Flutter, everything is a widget. Widgets are the basic building blocks of a Flutter app\'s UI. They describe how your app\'s view should look like given its current configuration and state.',
    ),
    FaqItem(
      question: 'How to hot reload in Flutter?',
      answer: 'Hot Reload lets you inject updated source code into a running application. To use it, simply save your code changes while the app is running in debug mode, and the changes will instantly reflect without restarting the app.',
    ),
    FaqItem(
      question: 'Can I use Flutter for web development?',
      answer: 'Yes, Flutter supports web development, allowing you to build highly interactive web applications using the same codebase as your mobile and desktop apps.',
    ),
    FaqItem(
      question: 'What is Dart?',
      answer: 'Dart is an object-oriented, class-based, garbage-collected programming language with C-style syntax. It can compile to either native code or JavaScript. It is the language Flutter apps are written in.',
    ),
  ];

  List _filteredFaqs = [];
  String _searchText = '';
  int? _expandedIndex; // Stores the index of the currently expanded FAQ within _filteredFaqs

  @override
  void initState() {
    super.initState();
    _filteredFaqs = _allFaqs; // Initialize with all FAQs
  }

  void _filterFaqs(String query) {
    setState(() {
      _searchText = query.toLowerCase();
      if (_searchText.isEmpty) {
        _filteredFaqs = _allFaqs;
      } else {
        _filteredFaqs = _allFaqs.where((faq) {
          // Filter by matching query in question or answer
          return faq.question.toLowerCase().contains(_searchText) ||
                 faq.answer.toLowerCase().contains(_searchText);
        }).toList();
      }
      _expandedIndex = null; // Collapse all FAQs when search query changes
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FAQ Accordion with Search'),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              decoration: InputDecoration(
                hintText: 'Search FAQs...',
                prefixIcon: const Icon(Icons.search),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(10.0),
                ),
              ),
              onChanged: _filterFaqs, // Call filter function on text change
            ),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: _filteredFaqs.length,
              itemBuilder: (context, index) {
                final faq = _filteredFaqs[index];
                return FaqAccordionTile(
                  faq: faq,
                  isExpanded: _expandedIndex == index, // Check if this item is currently expanded
                  onTap: () {
                    setState(() {
                      // Toggle expansion: if tapped item is already expanded, collapse it. Otherwise, expand it.
                      _expandedIndex = _expandedIndex == index ? null : index;
                    });
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

3.2. Initial Setup in main.dart

To run your application, update your main.dart file to display the FaqScreen as the home widget:


// main.dart
import 'package:flutter/material.dart';
import 'package:faq_app/screens/faq_screen.dart'; // Adjust path if necessary

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FAQ App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const FaqScreen(),
    );
  }
}

Conclusion

You have successfully created a dynamic FAQ accordion widget with a search filter in Flutter. This component enhances user experience by making information easily accessible and searchable. The architecture separates data models, individual UI components, and the main screen logic, promoting a clean and maintainable codebase.

You can further enhance this widget by:

  • Fetching FAQ data from an API or a local database.
  • Adding animations for expansion and collapse.
  • Implementing a clear button for the search bar.
  • Customizing the appearance to match your app's theme.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is