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

How to Create a Custom Chat Widget for Your FlutterFlow App

Build a real-time chat using a Firestore messages subcollection under each conversation document. Display messages in a reversed ListView ordered by timestamp descending so new messages appear at the bottom. Style message bubbles as Containers with different colors and alignment based on whether senderId matches the current user. Pin a TextField with a send IconButton at the bottom. Add a typing indicator by updating a typingUserId field on the conversation document.

What you'll learn

  • How to design a Firestore data model for conversations and messages
  • How to display messages in a reversed ListView with real-time updates
  • How to style message bubbles with conditional alignment and colors
  • How to implement a typing indicator using Firestore field updates
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner6 min read25-35 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Build a real-time chat using a Firestore messages subcollection under each conversation document. Display messages in a reversed ListView ordered by timestamp descending so new messages appear at the bottom. Style message bubbles as Containers with different colors and alignment based on whether senderId matches the current user. Pin a TextField with a send IconButton at the bottom. Add a typing indicator by updating a typingUserId field on the conversation document.

Building a Real-Time Chat Interface in FlutterFlow

Chat is a core feature for social apps, customer support, marketplaces, and collaboration tools. This tutorial builds a complete chat screen with real-time Firestore messaging, styled bubbles, and typing indicators using only the FlutterFlow visual builder.

Prerequisites

  • A FlutterFlow project with Firestore and authentication configured
  • A conversations collection in Firestore
  • Two test user accounts for sending and receiving messages

Step-by-step guide

1

Set up the Firestore data model for conversations and messages

Create a conversations collection with fields: participantIds (String Array), lastMessage (String), lastMessageTimestamp (Timestamp), typingUserId (String, nullable). Create a messages subcollection under each conversation with fields: text (String), senderId (String), senderName (String), timestamp (Timestamp), type (String: 'text'). Add indexes for messages ordered by timestamp descending. This subcollection pattern scales well — each conversation loads only its own messages.

Expected result: Firestore has conversations with a messages subcollection ready for real-time chat.

2

Build the chat page layout with reversed ListView and input bar

Create a ChatPage with Route Parameter conversationId. Use a Column layout. Add an Expanded widget containing a ListView set to reverse: true. Below the Expanded, add a Container with a Row: a TextField (flex: 1, hint: 'Type a message...', maxLines: 4) and an IconButton (send icon, Primary color). The reversed ListView shows newest messages at the bottom, matching how every chat app works. The input bar stays pinned at the bottom.

Expected result: A chat page with messages area on top and input bar pinned at the bottom.

3

Bind the ListView to a real-time Firestore query on messages

On the ListView, add a Backend Query: Query Collection on conversations/{conversationId}/messages, ordered by timestamp descending. Critically, disable Single Time Query so the query is real-time — new messages appear instantly without refreshing. Enable Generate Dynamic Children. Each child is a message bubble Component that receives text, senderId, senderName, and timestamp as Component Parameters.

Expected result: Messages from Firestore display in the ListView and update in real-time as new messages are sent.

4

Style message bubbles with conditional alignment and color

Create a MessageBubble Component with parameters: text, senderId, senderName, timestamp. The root widget is an Align widget. Set Conditional alignment: if senderId == currentUser.uid → Alignment.centerRight (sent), else → Alignment.centerLeft (received). Inside, a Container with borderRadius (rounded corners, flat on the side closest to the edge), background color (Primary for sent, grey100 for received), max width 75% of screen. Inside: Text message in white (sent) or black (received), and timestamp Text in small grey.

Expected result: Sent messages align right with primary color, received messages align left with grey background.

5

Implement the send action and typing indicator

On the send IconButton tap: check TextField is not empty → Create Document in messages subcollection (text, senderId: currentUser.uid, senderName: currentUser.displayName, timestamp: now, type: 'text') → Update conversation document (lastMessage: text, lastMessageTimestamp: now) → Clear TextField. For typing indicator: on TextField focus, update conversation typingUserId to currentUser.uid. On blur or send, set typingUserId to null. Show a typing indicator Component (three dots animation) above the input bar with Conditional Visibility: typingUserId != null AND typingUserId != currentUser.uid.

Expected result: Sending creates a message in Firestore visible to both users. The typing indicator shows when the other person is typing.

Complete working example

FlutterFlow Chat Setup
1FIRESTORE DATA MODEL:
2 conversations/{conversationId}
3 participantIds: ["uid1", "uid2"]
4 lastMessage: String
5 lastMessageTimestamp: Timestamp
6 typingUserId: String (nullable)
7 messages/{messageId}
8 text: String
9 senderId: String
10 senderName: String
11 timestamp: Timestamp
12 type: "text"
13
14PAGE: ChatPage
15 Route Parameter: conversationId (String)
16
17WIDGET TREE:
18 Column
19 Expanded
20 ListView (reverse: true)
21 Backend Query: messages, order by timestamp desc, real-time
22 Generate Dynamic Children MessageBubble Component
23 TypingIndicator Component
24 Conditional Visibility: typingUserId != null && != currentUser.uid
25 Layout: Row of 3 animated dots
26 Container (input bar, padding 8)
27 Row
28 Expanded TextField (hint: 'Type a message...', maxLines: 4)
29 IconButton (send, Primary)
30 On Tap:
31 1. Create Document: messages/ (text, senderId, timestamp)
32 2. Update Document: conversation (lastMessage, timestamp)
33 3. Clear TextField
34 4. Set typingUserId: null
35
36MESSAGE BUBBLE COMPONENT:
37 Align (Conditional: right if sent, left if received)
38 Container (maxWidth: 75%, borderRadius, bg: Primary/grey)
39 Column
40 Text (message text)
41 Text (timestamp, small, grey)

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

Why it's a problem: Not using a reversed ListView for the message list

How to avoid: Set reverse: true on the ListView and order the Firestore query by timestamp descending. Newest messages appear at the bottom automatically.

Why it's a problem: Using a Single Time Query instead of real-time for messages

How to avoid: Disable Single Time Query on the Backend Query so it uses real-time listeners. New messages appear instantly.

Why it's a problem: Incrementing a like count or message count without Firestore transactions

How to avoid: Use FieldValue.serverTimestamp() for timestamps and FieldValue.increment() for counts in Custom Actions, or use Firestore transactions.

Best practices

  • Use reversed ListView with timestamp descending order for natural chat layout
  • Enable real-time queries (disable Single Time Query) for instant message updates
  • Style message bubbles differently for sent vs received with conditional alignment and color
  • Pin the input bar at the bottom outside the scrollable area
  • Update the conversation document's lastMessage for display in conversation list
  • Add a typing indicator using a Firestore field that updates on TextField focus/blur
  • Limit the message query to the last 50 messages and load more on scroll for performance

Still stuck?

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

ChatGPT Prompt

I want to build a real-time chat screen in FlutterFlow using Firestore subcollections. Show the data model for conversations/messages, reversed ListView query setup, conditional message bubble styling for sent/received, send action flow, and typing indicator implementation.

FlutterFlow Prompt

Create a chat page with a scrollable list taking up most of the screen and an input row at the bottom with a text field and send button.

Frequently asked questions

Can I add image and file sharing to the chat?

Yes. Add a type field to messages (text/image/file). For images, upload via FlutterFlowUploadButton to Firebase Storage, save the download URL in the message, and render an Image widget conditionally when type is 'image'.

How do I implement read receipts?

Add a readBy array field to each message. When a user views a message, add their UID to readBy. Display a read indicator (double checkmark) when readBy contains the other participant's UID.

Can I build group chat with more than 2 users?

Yes. The participantIds array already supports multiple users. Display senderName in group bubbles and allow any participant to send. Filter conversations where participantIds array-contains the current user.

How do I handle message pagination for very long conversations?

Set a page size (50 messages) in the Backend Query. Enable infinite scroll to load older messages as the user scrolls up. Since the ListView is reversed, scrolling up loads older messages.

Does real-time chat use a lot of Firestore reads?

Each real-time listener counts as one read per document initially, then one read per change. For cost optimization, limit the initial query to 50 messages and paginate.

Can RapidDev help build a full chat system?

Yes. RapidDev can implement chat with image/file sharing, read receipts, push notifications, message reactions, message search, and end-to-end encryption.

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.