Matrix Power Levels#
Matrix power levels are integers assigned per-user in a room, controlling what actions a member can take. They are stored in the m.room.power_levels state event (state key ""). The standard tiers are 0 (default/restricted), 50 (moderator), and 100 (admin), but any integer is valid.
SDK Data Model#
In matrix-js-sdk, power level state is owned by RoomState and propagated to individual RoomMember objects.
IPowerLevelsContentβ the TypeScript interface form.room.power_levelscontent, definingusers,events,users_default,events_default,state_default,ban,kick,invite,redact, andnotifications.RoomMember.powerLevelβ the resolved integer level for the member; defaults to0. Set viasetPowerLevelEvent(), which readsusers[userId]first, thenusers_default, then falls back to0.RoomMember.powerLevelNormβ a0β100normalised value relative to the highest level in the room , used for visual ordering.RoomStateEvent.Membersis emitted when a member's power level changes , but only if the level actually changed β to avoid unnecessary re-renders in large rooms.
When a new member joins, RoomState.updateMember() immediately applies the existing m.room.power_levels event to that member.
Permission Checks#
RoomState exposes several helpers built on the power level event:
| Method | Purpose |
|---|---|
maySendEvent() | Normal event send permission |
maySendStateEvent() | State event send permission |
maySendRedactionForEvent() | Redaction permission |
hasSufficientPowerLevelFor() | Generic action check (ban, kick, redactβ¦) |
mayTriggerNotifOfType() | Notification trigger permission |
The core logic lives in maySendEventOfType(). When a m.room.power_levels event exists, state_default falls back to 50 if not explicitly set β matching the Matrix spec convention that state events require moderator-level permission by default. events_default falls back to 0 .
Spec Compliance Gap: Missing Power Levels Event#
When no m.room.power_levels event exists, maySendEventOfType() initialises stateDefault, eventsDefault, and powerLevel all to 0 and skips the entire conditional block. This means every user (at power level 0) passes the state_default = 0 check and can send any event, including state events. The Matrix spec states that if state_default is absent from an existing power levels event it should default to 50; but the SDK only applies that 50 fallback when the event exists β not when the event itself is missing. Rooms created without a m.room.power_levels event are therefore treated as fully open, which is a known area of spec divergence.
UI Role Label Mapping (matrix-react-sdk)#
Element Web maps numeric power levels to human-readable labels in src/Roles.ts:
levelRoleMap(usersDefault)β returns a record keyed by level number :undefinedβ "Default" (i18n keypower_level|default)0β "Restricted"usersDefaultβ "Default"50β "Moderator"100β "Admin"
textualPowerLevel(level, usersDefault)β looks up a level in the map; falls back to"Custom (N)"for any numeric level not in the map .
These functions are consumed by:
PowerSelectorβ the dropdown used in room settings to change permission requirements.UserInfoβ the right-panel user detail view, which callstextualPowerLevel(powerLevel, powerLevelUsersDefault)to show a role description.
Member List Badges#
MemberTile renders a visual badge for Admin (β₯ 100) and Moderator (β₯ 50) using a powerStatusMap . It finds the nearest threshold the member's level meets, so a user at level 75 gets the Moderator badge. The badge label text is resolved from the PowerLabel map in EntityTile.tsx, which translates PowerStatus.Admin and PowerStatus.Moderator to i18n strings.
Room Settings: Roles & Permissions Tab#
RolesRoomSettingsTab is the primary UI for viewing and editing power levels. It:
- Reads
plContentfromroom.currentState.getStateEvents(EventType.RoomPowerLevels, "")and falls back to{}if absent . - Populates default levels for well-known event types via
populateDefaultPlEvents(), usingstate_default(default 50) andevents_default(default 0) from the current event. - Sends a new
m.room.power_levelsstate event on change .
PowerLevelSelector lists privileged (above users_default) and muted (below users_default) users separately .
Key Source Files#
| File | Purpose |
|---|---|
src/models/room-state.ts | IPowerLevelsContent, permission checks, event propagation |
src/models/room-member.ts | powerLevel, powerLevelNorm, setPowerLevelEvent() |
src/Roles.ts | levelRoleMap(), textualPowerLevel() |
src/components/views/elements/PowerSelector.tsx | Role dropdown widget |
src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx | Roles & Permissions settings tab |
src/components/views/rooms/MemberTile.tsx | Admin/Moderator badge in member list |
src/components/views/rooms/EntityTile.tsx | PowerStatus enum, badge rendering |