Skip to content

Commit 448fc4b

Browse files
authored
Merge pull request #2473 from ably/chat/update-typing-docs
Chat: Update typing indicator API documentation
2 parents 2da9847 + 84662cd commit 448fc4b

File tree

1 file changed

+54
-12
lines changed

1 file changed

+54
-12
lines changed

content/chat/rooms/typing.textile

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,20 @@ The following is the structure of a typing event:
7272
"clemons",
7373
"zoranges",
7474
},
75+
"change": {
76+
"type": "typing.started",
77+
"clientId": "clemons"
78+
}
7579
}
7680
```
7781

7882
The following are the properties of a typing event:
7983

8084
|_. Property |_. Description |_. Type |
8185
| currentlyTyping | A set of all users currently typing. | Set |
86+
| change | The single change that resulted in the event. | Object |
87+
| | type: The type of change that occurred. | String |
88+
| | clientId: The @clientId@ of the user that triggered the change. | String |
8289

8390
You can use the size of the @currentlyTyping@ set to decide whether to display individual user names, or that multiple people are typing in your user interface.
8491

@@ -99,8 +106,9 @@ blang[react].
99106
blang[javascript,kotlin].
100107
```[javascript]
101108
// Initial subscription
102-
const { unsubscribe } = room.typing.subscribe((event) => {
103-
console.log(`${event.clientId} is currently typing...`);
109+
import { TypingEvent } from '@ably/chat';
110+
const { unsubscribe } = room.typing.subscribe((event: TypingEvent) => {
111+
console.log('Typing event received: ', event);
104112
});
105113

106114
// To remove the listener
@@ -125,30 +133,28 @@ blang[react,swift,kotlin].
125133
h2(#set). Set typing status
126134

127135
blang[javascript,swift,kotlin].
128-
Use the <span lang="javascript">"@typing.start()@":https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-js.Typing.html#start</span><span lang="swift">"@typing.start()@":https://sdk.ably.com/builds/ably/ably-chat-swift/main/AblyChat/documentation/ablychat/typing/start%28%29</span><span lang="kotlin">"@typing.start()@":https://sdk.ably.com/builds/ably/ably-chat-kotlin/main/dokka/chat-android/com.ably.chat/-typing/start.html</span> method to emit a typing event with @isTyping@ set to @true@.
136+
Use the <span lang="javascript">"@typing.keystroke()@":https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-js.Typing.html#start</span><span lang="swift">"@typing.start()@":https://sdk.ably.com/builds/ably/ably-chat-swift/main/AblyChat/documentation/ablychat/typing/start%28%29</span><span lang="kotlin">"@typing.start()@":https://sdk.ably.com/builds/ably/ably-chat-kotlin/main/dokka/chat-android/com.ably.chat/-typing/start.html</span> method to emit a typing event with @type@ set to @typing.started@.
129137

130138
blang[react].
131-
Use the "@start()@":https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-react.UseTypingResponse.html#start method available from the response of the @useTyping@ hook to emit an event when a user has started typing.
132-
133-
There is a timeout associated with start events. A stop event will be automatically emitted after it expires if one isn't received before the timeout. The length of this timeout is customizable using the @timeoutMs@ parameter that can be configured in the @RoomOptions@ that you set when you "create a room":/docs/chat/rooms#create. The default is 10000ms.
139+
Use the "@keystroke()@":https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-react.UseTypingResponse.html#keystroke method available from the response of the @useTyping@ hook to emit an event when a user has started typing.
134140

135141
```[javascript]
136-
await room.typing.start();
142+
await room.typing.keystroke();
137143
```
138144

139145
```[react]
140146
import { useTyping } from '@ably/chat';
141147

142148
const MyComponent = () => {
143-
const { start, currentlyTyping, error } = useTyping();
144-
const handleStartClick = () => {
145-
start();
149+
const { keystroke, currentlyTyping, error } = useTyping();
150+
const handleKeystrokeClick = () => {
151+
keystroke();
146152
};
147153

148154
return (
149155
<div>
150156
{error && <p>Typing Error: {error.message}</p>}
151-
<button onClick={handleStartClick}>Start Typing</button>
157+
<button onClick={handleKeystrokeClick}>Start Typing</button>
152158
<p>Currently typing: {currentlyTyping.join(', ')}</p>
153159
</div>
154160
);
@@ -199,13 +205,49 @@ try await room.typing.stop()
199205
room.typing.stop()
200206
```
201207

208+
h3(#frequency). Typing Event Frequency
209+
210+
The Typing feature includes a configurable timer that controls how often typing events are sent to the server. This timer is reset each time a new typing event is sent, it works as follows:
211+
- On the **first call** to @keystroke()@, the timer is set and an event is sent to the server.
212+
- **Subsequent calls** before the timer expires result in a no-op.
213+
- After the timer expires, a new typing event is sent and the timer is reset.
214+
- If @stop()@ is called, the timer is reset and a @typing.stopped@ event is sent to the server.
215+
216+
You can configure the length of this timer using the @heartbeatThrottleMs@ parameter in @RoomOptions@ (default: **10,000ms**).
217+
It is recommended that you call @keystroke()@ with every keypress, and the SDK will handle when and if to send a typing indicator to the server.
218+
219+
h3(#emulating-heartbeats). Emulating User Behavior
220+
221+
You can emulate user behavior (e.g., in chatbots) by setting a timeout to call @keystroke()@ at intervals equal to the @heartbeatThrottleMs@ plus a small delay, e.g. 200ms. This will ensure the typing indicator remains active.
222+
223+
h3(#grace-period). Grace Period for Typing Events
224+
225+
For the recipient of typing events:
226+
- The typing indicator remains active for the **duration** defined by the @heartbeatThrottleMs@ parameter, plus a predefined **2000ms grace period**.
227+
- Receiving a new typing event before the grace period ends will reset the timeout.
228+
- If the grace period ends without receiving a new typing event, the SDK will emit a @typing.stopped@ event for that client to any subscribed listeners.
229+
230+
**For example:** With the @heartbeatThrottleMs@ set to **10,000ms**, the typing indicator remains active for **12,000ms**. If no new typing event is received within this time, the SDK will emit a @typing.stopped@ event.
231+
232+
h3(#adjusting-timeout). Adjusting the Event Frequency
233+
234+
You can adjust the @heartbeatThrottleMs@ parameter to balance responsiveness and resource costs:
235+
- **Increase responsiveness**: Lower the value → More typing events are sent to the server → Higher cost as more messages are sent.
236+
- **Save resource costs**: Raise the value → Fewer typing events are sent to the server → Lower responsiveness, but less cost as fewer messages are sent overall.
237+
238+
This balance allows you to optimize cost and responsiveness based on your applications needs.
239+
240+
<aside data-type='note'>
241+
<p>All clients in a room must have the same timeout value configured. If not, typing indicators might not display correctly.</p>
242+
</aside>
243+
202244
h2(#retrieve). Retrieve a list of users that are currently typing
203245

204246
blang[javascript,swift,kotlin].
205247
Use the <span lang="javascript">"@typing.get()@":https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-js.Typing.html#get</span><span lang="swift">"@typing.get()@":https://sdk.ably.com/builds/ably/ably-chat-swift/main/AblyChat/documentation/ablychat/typing/get%28%29</span><span lang="kotlin">"@typing.get()@":https://sdk.ably.com/builds/ably/ably-chat-kotlin/main/dokka/chat-android/com.ably.chat/-typing/get.html</span> method to retrieve a set of @clientId@s for all users that are currently typing in the room:
206248

207249
```[javascript]
208-
const currentlyTypingClientIds = await room.typing.get();
250+
const currentlyTypingClientIds = room.typing.get();
209251
```
210252

211253
```[swift]

0 commit comments

Comments
 (0)