How the matrix-js-sdk models rooms, timelines, and the events that flow through them.
In Matrix, everything happens inside a room. A room is a persistent, shared conversation space identified by a roomId. It holds a timeline of MatrixEvent objects — messages, state changes, reactions, and more. The matrix-js-sdk gives you high-level models for both.
A Room object represents everything the SDK knows about a single Matrix room: its timeline, current and historical state, members, name, receipts, threads, and notification counts.
After the client has synced at least once (SyncState.Prepared), rooms are available through the client:
import { ClientEvent, SyncState } from "matrix-js-sdk";client.once(ClientEvent.Sync, (state) => { if (state !== SyncState.Prepared) return; // Get a single room by ID const room = client.getRoom("!roomId:server"); // Get all rooms const rooms = client.getRooms(); console.log(`Joined ${rooms.length} rooms`);});
const room = client.getRoom("!abc:matrix.org");if (!room) return;console.log(room.roomId); // "!abc:matrix.org"console.log(room.name); // Resolved display nameconsole.log(room.getJoinedMemberCount()); // Number of joined members// Current state events (m.room.name, m.room.topic, m.room.member, …)const state = room.currentState;// The live timeline for this roomconst timeline = room.getLiveTimeline();const events = timeline.getEvents();
const event: MatrixEvent = /* from timeline */;event.getId(); // event_idevent.getType(); // "m.room.message", "m.room.member", etc.event.getContent(); // Parsed content objectevent.getSender(); // "@alice:matrix.org"event.getTs(); // origin_server_tsevent.isEncrypted(); // true if the event was encryptedevent.isState(); // true if the event has a state_keyevent.getStateKey(); // the state_key valueevent.getRelation(); // m.relates_to if present
await client.sendTextMessage("!roomId:server", "Hello from matrix-js-sdk!");
The SDK queues outbound events locally and applies “local echo” — the sent event appears in the timeline immediately with an EventStatus of sending. If the request fails, the status transitions to not_sent. Always supply a MatrixScheduler if you want automatic retry on network errors.
When threadSupport: true is passed to startClient(), the SDK groups events that share a thread relation into Thread objects.
const room = client.getRoom("!roomId:server");// All threads in the roomconst threads = room?.getThreads();// A specific thread by its root event IDconst thread = room?.getThread("$rootEventId");// Events in a thread timelineconst threadEvents = thread?.timeline ?? [];
The RoomEvent.Timeline event fires for both the main timeline and thread timelines. Check event.threadRootId or the toStartOfTimeline parameter to distinguish them.
Member state is managed through RoomState. You can access current members and listen for changes:
import { RoomStateEvent } from "matrix-js-sdk";client.on(RoomStateEvent.Members, (event, state, member) => { const room = client.getRoom(state.roomId); if (!room) return; const memberList = state.getMembers(); console.log(room.name); for (const m of memberList) { console.log(`(${m.membership}) ${m.name}`); }});
When lazyLoadMembers: true is set in startClient(), member events are not fetched during initial sync. Call room.loadMembersIfNeeded() before accessing members to ensure they are populated.