Flutter Firebase Chat App – Part 6: Typing Indicator Implementation

Learn how to implement a typing indicator in a Flutter chat app using Firebase Firestore. Show real-time “User is typing…” updates efficiently.

Introduction

Typing indicators are a small but powerful feature that improves the real-time communication experience.

When a user starts typing, the other participant sees:

User is typing...

This creates a more natural conversation flow.

In this article we will implement:

  • Typing state in Firestore
  • Updating typing status
  • Real-time UI updates
  • Performance optimization

Typing Indicator Architecture

User starts typing
       ↓
Update Firestore typing status
       ↓
Other user listens to typing field
       ↓
UI shows "Typing..."

Firestore Conversation Structure

We store typing status in the conversation document.

conversations
   ├── conversationId
   │      ├── participants
   │      ├── lastMessage
   │      ├── typing

Example Typing Field

{
  "typing": {
    "user1": true,
    "user2": false
  }
}

Step 1: Update Typing Status

When the user starts typing:

await FirebaseFirestore.instance
  .collection('conversations')
  .doc(conversationId)
  .update({
    "typing.currentUserId": true
  });

Step 2: Stop Typing

When the message is sent or typing stops:

await FirebaseFirestore.instance
  .collection('conversations')
  .doc(conversationId)
  .update({
    "typing.currentUserId": false
  });

Step 3: Listen to Typing State

StreamBuilder(
  stream: FirebaseFirestore.instance
    .collection('conversations')
    .doc(conversationId)
    .snapshots(),
  builder: (context, snapshot) {

    if (!snapshot.hasData) {
      return SizedBox();
    }

    final data = snapshot.data!.data();

    bool isTyping =
      data['typing'][otherUserId] ?? false;

    if (isTyping) {
      return Text("User is typing...");
    }

    return SizedBox();
  },
);

Detect Text Input Changes

TextField(
  onChanged: (value) {

    if (value.isNotEmpty) {
      setTyping(true);
    } else {
      setTyping(false);
    }

  },
)

Typing Timeout Optimization

If the user stops typing but does not send the message, the typing state should automatically reset.

Timer(
  Duration(seconds: 3),
  () {
    setTyping(false);
  }
);

UI Example

Column(
  children: [

    MessageList(),

    if (isTyping)
      Text(
        "Typing...",
        style: TextStyle(
          fontStyle: FontStyle.italic
        ),
      ),

    MessageInput()

  ],
)

Performance Optimization

  • Avoid updating typing status too frequently
  • Use debounce or delay
  • Reset typing state automatically

Debounce Example

Timer? typingTimer;

void onTyping() {

  typingTimer?.cancel();

  setTyping(true);

  typingTimer = Timer(
    Duration(seconds: 2),
    () => setTyping(false)
  );

}

Security Rule Reminder

match /conversations/{conversationId} {
  allow update: if request.auth != null
    && request.auth.uid in resource.data.participants;
}

Common Mistakes

  • Updating typing state on every keystroke
  • Not resetting typing status
  • Writing typing status to message collection

Production Flow Summary

User types message
      ↓
Typing status updated
      ↓
Other user receives realtime update
      ↓
UI displays typing indicator
      ↓
User sends message
      ↓
Typing status reset

Conclusion

Typing indicators significantly improve the real-time feel of a messaging app.

By updating a lightweight typing field in Firestore, we can create smooth real-time interaction between users.

In Part 7, we will implement: Online / Offline User Status System.

Share

What's Your Reaction?

Like Like 0
Dislike Dislike 0
Love Love 0
Funny Funny 0
Angry Angry 0
Sad Sad 0
Wow Wow 0