Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Create a Custom Feedback Widget for Your FlutterFlow App

Build a lightweight inline 'Was this helpful?' Component with thumbs up/down IconButtons that saves feedback to a Firestore page_feedback collection. Thumbs down reveals a follow-up TextField for comments. An AnimatedSwitcher handles smooth cross-fade transitions between three states (asking, followUp, thanked). A persisted App State list tracks which pages the user already rated, preventing duplicate submissions on refresh.

What you'll learn

  • How to build a three-state feedback Component with asking, followUp, and thanked views
  • How to use AnimatedSwitcher in a Custom Widget for smooth cross-fade transitions
  • How to save thumbs up/down feedback with optional comments to Firestore
  • How to prevent duplicate submissions using persisted App State
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read20-25 minFlutterFlow Pro+ (Custom Widget required for AnimatedSwitcher)March 2026RapidDev Engineering Team
TL;DR

Build a lightweight inline 'Was this helpful?' Component with thumbs up/down IconButtons that saves feedback to a Firestore page_feedback collection. Thumbs down reveals a follow-up TextField for comments. An AnimatedSwitcher handles smooth cross-fade transitions between three states (asking, followUp, thanked). A persisted App State list tracks which pages the user already rated, preventing duplicate submissions on refresh.

Inline thumbs up/down feedback widget with Firestore persistence

Most feedback implementations use a full-screen form or a star-rating dialog. This tutorial takes a lighter approach: a compact inline widget that sits at the bottom of any content page and asks 'Was this helpful?' with two thumb icons. Thumbs up saves immediately and shows a thank-you message. Thumbs down reveals a single TextField for a brief comment before saving. AnimatedSwitcher cross-fades between the three states so transitions feel polished. A persisted App State list remembers which pages the user already rated, so refreshing the page shows the thank-you state instead of asking again.

Prerequisites

  • A FlutterFlow project with Firebase/Firestore connected
  • Firebase Authentication enabled with users signing in
  • Basic understanding of Component State and App State
  • FlutterFlow Pro plan (Custom Widget required for AnimatedSwitcher)

Step-by-step guide

1

Create the FeedbackWidget Component with three states managed by Component State

Create a new Component called FeedbackWidget. Add a Component Parameter called pageId (type String, required) — this identifies which page the feedback belongs to. Add a Component State variable called widgetState (type String, default value 'asking'). The initial UI is a Row with mainAxisSize: min, centered, containing a Text widget ('Was this helpful?'), a SizedBox (width 12), an IconButton with Icons.thumb_up_outlined (On Tap: triggers positive feedback flow), a SizedBox (width 4), and an IconButton with Icons.thumb_down_outlined (On Tap: triggers negative feedback flow). Wrap the entire Row in a Container with max height 48, horizontal padding 16, vertical padding 8, border (1px, Theme dividerColor), borderRadius 8, and background set to Theme surface color. This Container is the root of the Component.

Expected result: A compact inline widget renders with 'Was this helpful?' text and two thumb icons in a bordered container.

2

Handle thumbs up tap — save to Firestore and animate to thank-you state

On the thumbs_up IconButton On Tap action, build this Action Flow: Step 1 — Backend Call → Create Document in page_feedback collection with fields: pageId (from Component Parameter), userId (Authenticated User uid), isPositive (true), comment (''), timestamp (Current Timestamp). Step 2 — Update App State → add pageId to the feedbackSubmittedPages list (this is the persisted list you will create in Step 4). Step 3 — Update Component State → set widgetState to 'thanked'. The thank-you view is a Row with an Icon (Icons.check_circle, green, size 20), SizedBox (width 8), and Text ('Thanks for your feedback!', Theme bodyMedium). To animate: wrap the entire Component body in a Custom Widget using AnimatedSwitcher (duration 300ms, crossFadeState based on widgetState). Each state's root widget must have a unique ValueKey — ValueKey('asking'), ValueKey('thanked') — so AnimatedSwitcher detects the change and plays the cross-fade.

Expected result: Tapping thumbs up saves a positive feedback document to Firestore and cross-fades to a green checkmark with 'Thanks for your feedback!' text.

3

Handle thumbs down tap — show follow-up TextField then save with comment

On the thumbs_down IconButton On Tap action: Update Component State → set widgetState to 'followUp'. The follow-up view (shown when widgetState == 'followUp') is a Column (crossAxisAlignment: start) inside the same bordered Container, now with max height 120: Row 1 — Text ('What went wrong?', Theme bodyMedium, fontWeight bold). Row 2 — a TextField with hintText 'Tell us briefly...', maxLength 200, maxLines 2, and its value bound to a Component State variable called feedbackComment (type String). Row 3 — an Align (alignment: centerRight) containing a small ElevatedButton ('Submit', Theme primaryColor). On the Submit button On Tap: Step 1 — Backend Call → Create Document in page_feedback with pageId, userId, isPositive: false, comment: feedbackComment, timestamp. Step 2 — Update App State → add pageId to feedbackSubmittedPages. Step 3 — Update Component State → set widgetState to 'thanked'. This reuses the same thank-you view from Step 2. Give the follow-up Column a ValueKey('followUp') so AnimatedSwitcher animates correctly between all three states.

Expected result: Tapping thumbs down cross-fades to a text input asking what went wrong. After submitting, it saves the negative feedback with the comment and cross-fades to the thank-you state.

4

Prevent duplicate feedback with persisted App State list

Go to App State in the left panel and create a new variable: feedbackSubmittedPages, type List<String>, Persisted ON. This list survives app restarts because FlutterFlow stores persisted App State in SharedPreferences. Back in the FeedbackWidget Component, add an On Initialization action (Component Lifecycle): check if the current pageId exists in App State feedbackSubmittedPages using a Conditional Action — condition: feedbackSubmittedPages Contains pageId. If true → Update Component State → set widgetState to 'thanked' immediately (skipping the asking state). If false → do nothing (widgetState stays as 'asking'). This means returning users who already rated the page see the thank-you state right away.

Expected result: Users who already submitted feedback for a page see the thank-you state immediately on load. The asking state only appears for pages they have not yet rated.

5

Style and embed the widget at the bottom of content pages

Fine-tune the styling: the asking state Container has max height 48, the followUp Container expands to max height 120, and the thanked state Container returns to max height 48. Use AnimatedContainer instead of a plain Container for the outer wrapper so the height change animates smoothly (duration 300ms, curve: easeInOut). Set horizontal margin 16 and bottom margin 24 so the widget has breathing room from page edges. To embed: open any content page, scroll to the bottom of the widget tree, and drag in the FeedbackWidget Component. Set the pageId parameter to the page's route name or a unique identifier string (e.g., 'help-getting-started'). Repeat for every content page that needs feedback collection. The widget is self-contained — no page-level state or queries needed.

Expected result: A compact, styled feedback widget appears at the bottom of each content page, smoothly animating between states and respecting previous submissions.

Complete working example

FeedbackWidget Component Architecture
1Firestore Data Model:
2 page_feedback/{docId}
3 pageId: String ("help-getting-started")
4 userId: String (authenticated user UID)
5 isPositive: Boolean (true = thumbs up, false = thumbs down)
6 comment: String ("" for thumbs up, user text for thumbs down)
7 timestamp: Timestamp
8
9App State (Persisted):
10 feedbackSubmittedPages: List<String>
11 e.g. ["help-getting-started", "tutorial-auth-setup"]
12
13FeedbackWidget Component:
14 Parameters: pageId (String, required)
15 Component State:
16 widgetState: String ("asking" | "followUp" | "thanked")
17 feedbackComment: String ("")
18
19 On Initialization:
20 IF feedbackSubmittedPages.contains(pageId)
21 Set widgetState = "thanked"
22
23 AnimatedSwitcher (duration: 300ms, crossFadeState)
24
25 [widgetState == "asking"] ValueKey("asking")
26 AnimatedContainer (maxHeight: 48, border, surface bg)
27 Row (mainAxisSize: min, center)
28 Text ("Was this helpful?")
29 SizedBox (w: 12)
30 IconButton (Icons.thumb_up_outlined)
31 On Tap Create page_feedback (isPositive: true)
32 Add pageId to feedbackSubmittedPages
33 Set widgetState = "thanked"
34 SizedBox (w: 4)
35 IconButton (Icons.thumb_down_outlined)
36 On Tap Set widgetState = "followUp"
37
38 [widgetState == "followUp"] ValueKey("followUp")
39 AnimatedContainer (maxHeight: 120, border, surface bg)
40 Column (crossAxis: start, padding: 12)
41 Text ("What went wrong?", bold)
42 SizedBox (h: 8)
43 TextField (hint: "Tell us briefly...",
44 maxLength: 200, maxLines: 2,
45 bound to feedbackComment)
46 Align (centerRight)
47 ElevatedButton ("Submit")
48 On Tap Create page_feedback
49 (isPositive: false,
50 comment: feedbackComment)
51 Add pageId to feedbackSubmittedPages
52 Set widgetState = "thanked"
53
54 [widgetState == "thanked"] ValueKey("thanked")
55 AnimatedContainer (maxHeight: 48, border, surface bg)
56 Row (mainAxisSize: min, center)
57 Icon (Icons.check_circle, green, size: 20)
58 SizedBox (w: 8)
59 Text ("Thanks for your feedback!")

Common mistakes when creating a Custom Feedback Widget for Your FlutterFlow App

Why it's a problem: Not preventing duplicate submissions — user refreshes the page and can vote again

How to avoid: Use a persisted App State list (feedbackSubmittedPages). On Component load, check if the current pageId is in the list. If yes, show the thanked state immediately. On submit, add the pageId to the list. Persisted App State survives app restarts via SharedPreferences.

Why it's a problem: Using a full-screen Dialog or bottom sheet for feedback instead of an inline widget

How to avoid: Keep the widget inline at the bottom of the content. A 48px-tall Row with two icons is non-intrusive. Users who want to give feedback can do so without leaving the page context.

Why it's a problem: AnimatedSwitcher not animating — child widgets swap instantly without cross-fade

How to avoid: Add a unique ValueKey to each state's root widget: ValueKey('asking'), ValueKey('followUp'), ValueKey('thanked'). AnimatedSwitcher detects the key change and plays the cross-fade transition.

Best practices

  • Use a Component Parameter for pageId so the same FeedbackWidget works on any page without modification
  • Keep the asking state compact (max height 48px) so it does not compete with page content for attention
  • Set AnimatedSwitcher duration to 200-300ms — fast enough to feel responsive, slow enough to be visible
  • Use AnimatedContainer for the outer wrapper so height changes between states animate smoothly
  • Persist the feedbackSubmittedPages App State list so duplicate prevention survives app restarts
  • Add maxLength: 200 on the follow-up TextField to keep comments concise and prevent Firestore bloat
  • Use a consistent slug-style naming convention for pageId values to simplify Firestore queries and aggregation

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Design a Firestore data model for collecting inline page feedback with thumbs up/down and optional text comments. Include fields for pageId, userId, isPositive boolean, comment, and timestamp. Give me Firestore security rules that let authenticated users create feedback and only read their own submissions.

FlutterFlow Prompt

Create a Component called FeedbackWidget with a pageId parameter. Show a Row with 'Was this helpful?' text and thumbs up/down icon buttons. Thumbs up saves positive feedback to Firestore and shows a thank-you message. Thumbs down reveals a TextField for a comment then saves negative feedback. Use Component State to track the current view state.

Frequently asked questions

How is this different from the full feedback screen tutorial?

The feedback screen tutorial builds a dedicated page with star ratings, text areas, and category dropdowns — suited for detailed feedback collection. This widget is a compact inline element (48px tall) with a binary thumbs up/down question, designed to be embedded at the bottom of any content page without interrupting the reading flow.

Can I embed this widget on every page in my app?

Yes. Because FeedbackWidget is a Component with a pageId parameter, you drag it onto any page and pass a unique identifier string. The persisted App State list handles duplicate prevention per page, so each page tracks feedback independently.

How do I view the collected feedback data?

Open the Firebase Console, navigate to Firestore, and browse the page_feedback collection. Filter by pageId to see feedback for a specific page, or filter by isPositive == false to find pages with negative feedback. For a better experience, build an admin page in FlutterFlow with a ListView querying page_feedback ordered by timestamp descending.

What happens if the user clears their app data or uses a different device?

Persisted App State uses SharedPreferences, which is local to the device. If the user clears app data or switches devices, the feedbackSubmittedPages list resets and they can submit feedback again. To prevent this, query Firestore on Component load to check if a page_feedback document exists for the current userId and pageId — but this adds a read cost per widget load.

Can I add more feedback options like a star rating or emoji scale?

Yes, but that changes the widget's purpose. The strength of this design is its simplicity — a binary question has the highest response rate because it requires minimal effort. If you need richer feedback, use the full feedback screen tutorial instead, or add a third 'Suggest improvement' option that opens a separate page.

Can RapidDev help build a feedback analytics dashboard?

Yes. Aggregating feedback across hundreds of pages, calculating satisfaction percentages, spotting trends over time, and building drill-down views requires Cloud Functions for server-side aggregation and a custom admin interface. RapidDev can architect the full feedback analytics pipeline.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.