# Typing
The `Typing` interface provides methods for sending and receiving typing indicators in a chat room. Access it via `room.typing`.
#### Javascript
```
const typing = room.typing;
```
## Properties
The `Typing` interface has the following properties:
| Property | Description | Type |
| --- | --- | --- |
| current | The current set of client IDs who are typing in the room. | `Set` |
## Start typing
`typing.keystroke(): Promise`
Sends a typing started event to notify other users that the current user is typing.
Events are throttled according to the [`heartbeatThrottleMs`](https://ably.com/docs/chat/api/javascript/rooms.md#get) room option to prevent excessive network traffic. If called within the throttle interval, the operation becomes a no-op. Multiple rapid calls are serialized to maintain consistency.
The room must be [attached](https://ably.com/docs/chat/api/javascript/room.md#attach) and the connection must be in the [`connected`](https://ably.com/docs/chat/api/javascript/connection.md) state.
### Javascript
```
// Call this when the user starts typing
await room.typing.keystroke();
```
### Returns
`Promise`
Returns a promise. The promise is fulfilled when the typing event has been sent, or rejected with an [`ErrorInfo`](https://ably.com/docs/chat/api/javascript/chat-client.md#errorinfo) object.
## Stop typing
`typing.stop(): Promise`
Sends a typing stopped event to notify other users that the current user has stopped typing.
If the user is not currently typing, this operation is a no-op. Multiple rapid calls are serialized to maintain consistency.
The room must be [attached](https://ably.com/docs/chat/api/javascript/room.md#attach) and the connection must be in the [`connected`](https://ably.com/docs/chat/api/javascript/connection.md) state.
### Javascript
```
// Call this when the user stops typing or clears the input
await room.typing.stop();
```
### Returns
`Promise`
Returns a promise. The promise is fulfilled when the stop event has been sent, or rejected with an [`ErrorInfo`](https://ably.com/docs/chat/api/javascript/chat-client.md#errorinfo) object.
## Subscribe to typing events
`typing.subscribe(listener: TypingListener): Subscription`
Subscribes to typing events from users in the chat room. Receives updates whenever a user starts or stops typing, providing real-time feedback about who is currently composing messages.
The room must be [attached](https://ably.com/docs/chat/api/javascript/room.md#attach) to receive typing events.
### Javascript
```
const { unsubscribe } = room.typing.subscribe((event) => {
console.log('Currently typing:', Array.from(event.currentlyTyping));
});
// To stop receiving typing events
unsubscribe();
```
### Parameters
The `subscribe()` method takes the following parameters:
| Parameter | Required | Description | Type |
| --- | --- | --- | --- |
| listener | Required | Callback invoked when the typing state changes. | |
| Property | Description | Type |
| --- | --- | --- |
| type | The type of the event. Always `SetChanged`. | |
| currentlyTyping | Set of client IDs currently typing in the room. | `Set` |
| change | Information about the specific change that triggered this event. | |
| Value | Description |
| --- | --- |
| SetChanged | The set of currently typing users has changed. The value is `typing.set.changed`. |
| Property | Description | Type |
| --- | --- | --- |
| clientId | The client ID whose typing state changed. | String |
| type | Whether the user started or stopped typing. | |
| Value | Description |
| --- | --- |
| Started | A user has started typing. The value is `typing.started`. |
| Stopped | A user has stopped typing. The value is `typing.stopped`. |
### Returns
`Subscription`
Returns an object with the following methods:
#### Unsubscribe from typing events
`unsubscribe(): void`
Call `unsubscribe()` to stop receiving typing events.
## Example
### Javascript
```
const room = await chatClient.rooms.get('my-room', {
typing: {
heartbeatThrottleMs: 5000 // Throttle typing events to every 5 seconds
}
});
await room.attach();
// Subscribe to typing events
const { unsubscribe } = room.typing.subscribe((event) => {
const typingUsers = Array.from(event.currentlyTyping);
if (typingUsers.length === 0) {
console.log('No one is typing');
} else if (typingUsers.length === 1) {
console.log(`${typingUsers[0]} is typing...`);
} else {
console.log(`${typingUsers.join(', ')} are typing...`);
}
});
// Integrate with an input field
const inputField = document.getElementById('message-input');
inputField.addEventListener('input', async () => {
if (inputField.value.length > 0) {
await room.typing.keystroke();
} else {
await room.typing.stop();
}
});
inputField.addEventListener('blur', async () => {
await room.typing.stop();
});
// Check who is currently typing
console.log('Currently typing:', room.typing.current);
// Clean up
unsubscribe();
```