diff --git a/src/domain/session/RoomGridViewModel.js b/src/domain/session/RoomGridViewModel.js
index b9b62153..535d454a 100644
--- a/src/domain/session/RoomGridViewModel.js
+++ b/src/domain/session/RoomGridViewModel.js
@@ -32,10 +32,11 @@ export class RoomGridViewModel extends ViewModel {
 
         this._width = options.width;
         this._height = options.height;
-        this._createRoomViewModel = options.createRoomViewModel;
+        this._createRoomOrInviteViewModel = options.createRoomOrInviteViewModel;
 
         this._selectedIndex = 0;
         this._viewModels = [];
+        this._replaceInviteWithRoom = this._replaceInviteWithRoom.bind(this);
         this._setupNavigation();
     }
 
@@ -63,6 +64,24 @@ export class RoomGridViewModel extends ViewModel {
         // initial focus for a room is set by initializeRoomIdsAndTransferVM
     }
 
+    _replaceInviteWithRoom(roomId) {
+        const index = this._viewModels.findIndex(vm => vm?.id === roomId);
+        if (index === -1) {
+            return;
+        }
+        this._viewModels[index] = this.disposeTracked(this._viewModels[index]);
+        // this will create a RoomViewModel because the invite is already
+        // removed from the collection (see Invite.afterSync)
+        const roomVM = this._createRoomOrInviteViewModel(roomId, this._replaceInviteWithRoom);
+        if (roomVM) {
+            this._viewModels[index] = this.track(roomVM);
+            if (this.focusIndex === index) {
+                roomVM.focus();
+            }
+        }
+        this.emitChange();
+    }
+
     roomViewModelAt(i) {
         return this._viewModels[i];
     }
@@ -128,7 +147,7 @@ export class RoomGridViewModel extends ViewModel {
                     this._viewModels[i] = this.disposeTracked(vm);
                 }
                 if (newId) {
-                    const newVM = this._createRoomViewModel(newId);
+                    const newVM = this._createRoomOrInviteViewModel(newId, this._replaceInviteWithRoom);
                     if (newVM) {
                         this._viewModels[i] = this.track(newVM);
                     }
@@ -211,7 +230,7 @@ export function tests() {
         "initialize with duplicate set of rooms": assert => {
             const navigation = createNavigationForRoom(["c", "a", "b", undefined, "a"], "a");
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: id => new RoomVMMock(id),
+                createRoomOrInviteViewModel: id => new RoomVMMock(id),
                 navigation,
                 width: 3,
                 height: 2,
@@ -228,7 +247,7 @@ export function tests() {
         "transfer room view model": assert => {
             const navigation = createNavigationForRoom(["a"], "a");
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: () => assert.fail("no vms should be created"),
+                createRoomOrInviteViewModel: () => assert.fail("no vms should be created"),
                 navigation,
                 width: 3,
                 height: 2,
@@ -242,7 +261,7 @@ export function tests() {
         "reject transfer for non-matching room view model": assert => {
             const navigation = createNavigationForRoom(["a"], "a");
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: id => new RoomVMMock(id),
+                createRoomOrInviteViewModel: id => new RoomVMMock(id),
                 navigation,
                 width: 3,
                 height: 2,
@@ -256,7 +275,7 @@ export function tests() {
         "created & released room view model is not disposed": assert => {
             const navigation = createNavigationForRoom(["a"], "a");
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: id => new RoomVMMock(id),
+                createRoomOrInviteViewModel: id => new RoomVMMock(id),
                 navigation,
                 width: 3,
                 height: 2,
@@ -270,7 +289,7 @@ export function tests() {
         "transfered & released room view model is not disposed": assert => {
             const navigation = createNavigationForRoom([undefined, "a"], "a");
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: () => assert.fail("no vms should be created"),
+                createRoomOrInviteViewModel: () => assert.fail("no vms should be created"),
                 navigation,
                 width: 3,
                 height: 2,
@@ -285,7 +304,7 @@ export function tests() {
         "try release non-existing room view model is": assert => {
             const navigation = createNavigationForEmptyTile([undefined, "b"], 3);
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: id => new RoomVMMock(id),
+                createRoomOrInviteViewModel: id => new RoomVMMock(id),
                 navigation,
                 width: 3,
                 height: 2,
@@ -297,7 +316,7 @@ export function tests() {
         "initial focus is set to empty tile": assert => {
             const navigation = createNavigationForEmptyTile(["a"], 1);
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: id => new RoomVMMock(id),
+                createRoomOrInviteViewModel: id => new RoomVMMock(id),
                 navigation,
                 width: 3,
                 height: 2,
@@ -309,7 +328,7 @@ export function tests() {
         "change room ids after creation": assert => {
             const navigation = createNavigationForRoom(["a", "b"], "a");
             const gridVM = new RoomGridViewModel({
-                createRoomViewModel: id => new RoomVMMock(id),
+                createRoomOrInviteViewModel: id => new RoomVMMock(id),
                 navigation,
                 width: 3,
                 height: 2,
diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js
index 2f7e341e..4992c9e2 100644
--- a/src/domain/session/SessionViewModel.js
+++ b/src/domain/session/SessionViewModel.js
@@ -15,8 +15,10 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
+import {removeRoomFromPath} from "../navigation/index.js";
 import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js";
 import {RoomViewModel} from "./room/RoomViewModel.js";
+import {InviteViewModel} from "./room/InviteViewModel.js";
 import {LightboxViewModel} from "./room/LightboxViewModel.js";
 import {SessionStatusViewModel} from "./SessionStatusViewModel.js";
 import {RoomGridViewModel} from "./RoomGridViewModel.js";
@@ -39,6 +41,8 @@ export class SessionViewModel extends ViewModel {
         this._settingsViewModel = null;
         this._currentRoomViewModel = null;
         this._gridViewModel = null;
+        this._replaceInviteWithRoom = this._replaceInviteWithRoom.bind(this);
+        this._createRoomOrInviteViewModel = this._createRoomOrInviteViewModel.bind(this);
         this._setupNavigation();
     }
 
@@ -84,15 +88,8 @@ export class SessionViewModel extends ViewModel {
         this._sessionStatusViewModel.start();
     }
 
-    get activeSection() {
-        if (this._currentRoomViewModel) {
-            return this._currentRoomViewModel.id;
-        } else if (this._gridViewModel) {
-            return "roomgrid";
-        } else if (this._settingsViewModel) {
-            return "settings";
-        }
-        return "placeholder";
+    get activeMiddleViewModel() {
+        return this._currentRoomViewModel || this._gridViewModel || this._settingsViewModel;
     }
 
     get roomGridViewModel() {
@@ -127,7 +124,7 @@ export class SessionViewModel extends ViewModel {
                 this._gridViewModel = this.track(new RoomGridViewModel(this.childOptions({
                     width: 3,
                     height: 2,
-                    createRoomViewModel: roomId => this._createRoomViewModel(roomId),
+                    createRoomOrInviteViewModel: this._createRoomOrInviteViewModel,
                 })));
                 if (this._gridViewModel.initializeRoomIdsAndTransferVM(roomIds, this._currentRoomViewModel)) {
                     this._currentRoomViewModel = this.untrack(this._currentRoomViewModel);
@@ -138,6 +135,7 @@ export class SessionViewModel extends ViewModel {
                 this._gridViewModel.setRoomIds(roomIds);
             }
         } else if (this._gridViewModel && !roomIds) {
+            // closing grid, try to show focused room in grid
             if (currentRoomId) {
                 const vm = this._gridViewModel.releaseRoomViewModel(currentRoomId.value);
                 if (vm) {
@@ -152,7 +150,7 @@ export class SessionViewModel extends ViewModel {
             this._gridViewModel = this.disposeTracked(this._gridViewModel);
         }
         if (changed) {
-            this.emitChange("activeSection");
+            this.emitChange("activeMiddleViewModel");
         }
     }
 
@@ -169,11 +167,50 @@ export class SessionViewModel extends ViewModel {
         return roomVM;
     }
 
+    _createInviteViewModel(roomId, replaceInviteWithRoom) {
+        const invite = this._sessionContainer.session.invites.get(roomId);
+        if (!invite) {
+            return null;
+        }
+        return new InviteViewModel(this.childOptions({
+            invite,
+            mediaRepository: this._sessionContainer.session.mediaRepository,
+            closeCallback: accepted => this._closeInvite(roomId, accepted, replaceInviteWithRoom),
+        }));
+    }
+
+    _createRoomOrInviteViewModel(roomId, replaceInviteWithRoom) {
+        const inviteVM = this._createInviteViewModel(roomId, replaceInviteWithRoom);
+        if (inviteVM) {
+            return inviteVM;
+        }
+        return this._createRoomViewModel(roomId);
+    }
+
+    _closeInvite(roomId, accepted, replaceInviteWithRoom) {
+        if (accepted) {
+            replaceInviteWithRoom(roomId);
+        } else {
+            // close invite
+            this.navigation.applyPath(removeRoomFromPath(this.navigation.path, roomId));
+        }
+    }
+
+    _replaceInviteWithRoom(roomId) {
+        this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
+        const roomVM = this._createRoomViewModel(roomId);
+        if (roomVM) {
+            this._currentRoomViewModel = this.track(roomVM);
+        }
+        this.emitChange("activeMiddleViewModel");
+    }
+
     _updateRoom(roomId) {
         if (!roomId) {
+            // closing invite or room view?
             if (this._currentRoomViewModel) {
                 this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
-                this.emitChange("currentRoom");
+                this.emitChange("activeMiddleViewModel");
             }
             return;
         }
@@ -182,11 +219,11 @@ export class SessionViewModel extends ViewModel {
             return;
         }
         this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
-        const roomVM = this._createRoomViewModel(roomId);
+        const roomVM = this._createRoomOrInviteViewModel(roomId, this._replaceInviteWithRoom);
         if (roomVM) {
             this._currentRoomViewModel = this.track(roomVM);
         }
-        this.emitChange("currentRoom");
+        this.emitChange("activeMiddleViewModel");
     }
 
     _updateSettings(settingsOpen) {
@@ -199,7 +236,7 @@ export class SessionViewModel extends ViewModel {
             })));
             this._settingsViewModel.load();
         }
-        this.emitChange("activeSection");
+        this.emitChange("activeMiddleViewModel");
     }
 
     _updateLightbox(eventId) {
diff --git a/src/platform/web/ui/session/SessionView.js b/src/platform/web/ui/session/SessionView.js
index fa7a492a..e05d97ad 100644
--- a/src/platform/web/ui/session/SessionView.js
+++ b/src/platform/web/ui/session/SessionView.js
@@ -34,16 +34,15 @@ export class SessionView extends TemplateView {
         }, [
             t.view(new SessionStatusView(vm.sessionStatusViewModel)),
             t.view(new LeftPanelView(vm.leftPanelViewModel)),
-            t.mapView(vm => vm.activeSection, activeSection => {
-                switch (activeSection) {
-                    case "roomgrid":
-                        return new RoomGridView(vm.roomGridViewModel);
-                    case "placeholder":
-                        return new StaticView(t => t.div({className: "room-placeholder"}, t.h2(vm.i18n`Choose a room on the left side.`)));
-                    case "settings":
-                        return new SettingsView(vm.settingsViewModel);
-                    default: //room id
+            t.mapView(vm => vm.activeMiddleViewModel, () => {
+                if (vm.roomGridViewModel) {
+                    return new RoomGridView(vm.roomGridViewModel);
+                } else if (vm.settingsViewModel) {
+                    return new SettingsView(vm.settingsViewModel);
+                } else if (vm.currentRoomViewModel) {
                         return new RoomView(vm.currentRoomViewModel);
+                } else {
+                    return new StaticView(t => t.div({className: "room-placeholder"}, t.h2(vm.i18n`Choose a room on the left side.`)));
                 }
             }),
             t.mapView(vm => vm.lightboxViewModel, lightboxViewModel => lightboxViewModel ? new LightboxView(lightboxViewModel) : null)