Feature: Typing Indicators #18
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom#18
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrated from GitHub issue icub3d/decentcom#18
Original Author: @icub3d
Original Date: 2026-04-15T14:15:43Z
Feature: Typing Indicators
Overview
Show real-time typing indicators when other users are composing messages in a channel or DM. The client broadcasts typing events through the WebSocket gateway, and other clients in the same channel display a "User is typing..." indicator with appropriate debounce and timeout logic to avoid flickering.
Background
The architecture doc (
docs/design/architecture.md) lists typing indicators as a core WebSocket gateway responsibility. The storage doc (docs/design/storage.md) explicitly notes that presence state (including typing) is entirely ephemeral and maintained in memory only — it is never persisted. Typing state is cleared on server restart and clients re-establish on reconnect.Requirements
VIEW_CHANNELpermission receive themDesign
API / Interface Changes
New gateway client-to-server event:
Sent by the client when the user begins typing. The client is responsible for debouncing (send at most once per 5 seconds while the user continues typing).
New gateway server-to-client event:
Broadcast to all other users subscribed to the channel.
No REST endpoint is needed — typing is purely a real-time ephemeral event.
Data Model Changes
No database changes. Typing state is held in-memory on the server in a structure like:
A background task periodically prunes entries older than the timeout threshold (8 seconds).
Component Changes
Server (
server/):server/src/gateway/events.rs— AddTYPING_STARTto the event type enumserver/src/gateway/handler.rs— Handle incomingTYPING_STARTevents: validate channel subscription, checkVIEW_CHANNELpermission, update in-memory typing state, broadcast to other subscribersserver/src/gateway/typing.rs— New module:TypingStatestruct, insertion, pruning logic, background cleanup taskClient (
client/):client/src/hooks/useTyping.ts— New hook: manages sending typing events with 5-second debounce, resets on message sendclient/src/components/TypingIndicator.tsx— New component: displays "X is typing...", "X and Y are typing...", or "Several people are typing..." with animated dotsclient/src/components/MessageInput.tsx— IntegrateuseTypinghook to fire typing events on keystrokesclient/src/stores/channelStore.ts— Add typing users state per channel, update onTYPING_STARTevents, clear on timeout or message receiptclient/src/gateway/handlers.ts— Add handler for incomingTYPING_STARTeventsTask List
Server
TYPING_STARTOp added to gateway event enum inshared/src/lib.rsserver/src/gateway/typing.rswithTypingStatestruct and methods:set_typing,get_typing,prune_expiredserver/src/main.rscallsprune_expired()every 2 secondsTYPING_STARThandled inserver/src/gateway/handler.rs: updatesTypingState, broadcasts viabroadcast_to_channel_except(excludes sender)Client
client/src/stores/channelStore.tsTYPING_STARThandler inclient/src/gateway/handlers.tsthat updates the channel store and sets an 8-second expiry timer per userMESSAGE_CREATEevent arrives from that user in that channeluseTypinghook inclient/src/hooks/useTyping.tswith 5-second debounce: sendsTYPING_STARTon first keystroke, suppresses repeats for 5 seconds, stops on message sendTypingIndicator.tsxcomponent with animated dots and user name displayuseTypingintoMessageInput.tsx(fire on input change)TypingIndicatorbelow the message input area in the channel viewTest List
TypingState::set_typingadds user,prune_expiredremoves stale entries (typing.rs unit tests)TYPING_STARTeventOpen Questions