diff --git a/src/components/views/rooms/MemberList.tsx b/src/components/views/rooms/MemberList.tsx
index a0b9cc0f70..582d329310 100644
--- a/src/components/views/rooms/MemberList.tsx
+++ b/src/components/views/rooms/MemberList.tsx
@@ -28,7 +28,6 @@ import {
     RoomStateEvent,
     User,
     UserEvent,
-    JoinRule,
     EventType,
     ClientEvent,
 } from "matrix-js-sdk/src/matrix";
@@ -54,6 +53,8 @@ import { shouldShowComponent } from "../../../customisations/helpers/UIComponent
 import { UIComponent } from "../../../settings/UIFeature";
 import PosthogTrackers from "../../../PosthogTrackers";
 import { SDKContext } from "../../../contexts/SDKContext";
+import { canInviteTo } from "../../../utils/room/canInviteTo";
+import { inviteToRoom } from "../../../utils/room/inviteToRoom";
 
 const INITIAL_LOAD_NUM_MEMBERS = 30;
 const INITIAL_LOAD_NUM_INVITED = 5;
@@ -132,9 +133,7 @@ export default class MemberList extends React.Component<IProps, IState> {
         const cli = MatrixClientPeg.safeGet();
         const room = cli.getRoom(this.props.roomId);
 
-        return (
-            !!room?.canInvite(cli.getSafeUserId()) || !!(room?.isSpaceRoom() && room.getJoinRule() === JoinRule.Public)
-        );
+        return !!room && canInviteTo(room);
     }
 
     private getMembersState(invitedMembers: Array<RoomMember>, joinedMembers: Array<RoomMember>): IState {
@@ -365,32 +364,25 @@ export default class MemberList extends React.Component<IProps, IState> {
         let inviteButton: JSX.Element | undefined;
 
         if (room?.getMyMembership() === "join" && shouldShowComponent(UIComponent.InviteUsers)) {
-            let inviteButtonText = _t("room|invite_this_room");
-            if (room.isSpaceRoom()) {
-                inviteButtonText = _t("space|invite_this_space");
-            }
+            const inviteButtonText = room.isSpaceRoom() ? _t("space|invite_this_space") : _t("room|invite_this_room");
+
+            const button = (
+                <Button
+                    size="sm"
+                    kind="secondary"
+                    className="mx_MemberList_invite"
+                    onClick={this.onInviteButtonClick}
+                    disabled={!this.state.canInvite}
+                >
+                    <UserAddIcon width="1em" height="1em" />
+                    {inviteButtonText}
+                </Button>
+            );
 
             if (this.state.canInvite) {
-                inviteButton = (
-                    <Button
-                        size="sm"
-                        kind="secondary"
-                        className="mx_MemberList_invite"
-                        onClick={this.onInviteButtonClick}
-                    >
-                        <UserAddIcon width="1em" height="1em" />
-                        {inviteButtonText}
-                    </Button>
-                );
+                inviteButton = button;
             } else {
-                inviteButton = (
-                    <Tooltip label={_t("member_list|invite_button_no_perms_tooltip")}>
-                        <Button size="sm" kind="secondary" className="mx_MemberList_invite" onClick={() => {}}>
-                            <UserAddIcon width="1em" height="1em" />
-                            {inviteButtonText}
-                        </Button>
-                    </Tooltip>
-                );
+                inviteButton = <Tooltip label={_t("member_list|invite_button_no_perms_tooltip")}>{button}</Tooltip>;
             }
         }
 
@@ -454,15 +446,9 @@ export default class MemberList extends React.Component<IProps, IState> {
     private onInviteButtonClick = (ev: ButtonEvent): void => {
         PosthogTrackers.trackInteraction("WebRightPanelMemberListInviteButton", ev);
 
-        if (MatrixClientPeg.safeGet().isGuest()) {
-            dis.dispatch({ action: "require_registration" });
-            return;
-        }
+        const cli = MatrixClientPeg.safeGet();
+        const room = cli.getRoom(this.props.roomId)!;
 
-        // open the room inviter
-        dis.dispatch({
-            action: "view_invite",
-            roomId: this.props.roomId,
-        });
+        inviteToRoom(room);
     };
 }
diff --git a/test/components/views/rooms/MemberList-test.tsx b/test/components/views/rooms/MemberList-test.tsx
index f9f591b373..1ba7151a32 100644
--- a/test/components/views/rooms/MemberList-test.tsx
+++ b/test/components/views/rooms/MemberList-test.tsx
@@ -16,21 +16,37 @@ limitations under the License.
 */
 
 import React from "react";
-import { act, render, RenderResult, screen } from "@testing-library/react";
+import { act, fireEvent, render, RenderResult, screen } from "@testing-library/react";
 import { Room, MatrixClient, RoomState, RoomMember, User, MatrixEvent } from "matrix-js-sdk/src/matrix";
 import { compare } from "matrix-js-sdk/src/utils";
+import { mocked, MockedObject } from "jest-mock";
 
 import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
 import * as TestUtils from "../../../test-utils";
 import MemberList from "../../../../src/components/views/rooms/MemberList";
 import { SDKContext } from "../../../../src/contexts/SDKContext";
 import { TestSdkContext } from "../../../TestSdkContext";
+import {
+    filterConsole,
+    flushPromises,
+    getMockClientWithEventEmitter,
+    mockClientMethodsUser,
+} from "../../../test-utils";
+import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents";
+import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
+
+jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({
+    shouldShowComponent: jest.fn(),
+}));
 
 function generateRoomId() {
     return "!" + Math.random().toString().slice(2, 10) + ":domain";
 }
 
 describe("MemberList", () => {
+    filterConsole(
+        "Age for event was not available, using `now - origin_server_ts` as a fallback. If the device clock is not correct issues might occur.",
+    );
     function createRoom(opts = {}) {
         const room = new Room(generateRoomId(), client, client.getUserId()!);
         if (opts) {
@@ -331,5 +347,93 @@ describe("MemberList", () => {
             );
             expect(await screen.findByText(/User's server unreachable/)).toBeInTheDocument();
         });
+
+        describe("Invite button", () => {
+            const roomId = "!room:server.org";
+            let client!: MockedObject<MatrixClient>;
+            let room!: Room;
+
+            beforeEach(function () {
+                mocked(shouldShowComponent).mockReturnValue(true);
+                client = getMockClientWithEventEmitter({
+                    ...mockClientMethodsUser(),
+                    getRoom: jest.fn(),
+                    hasLazyLoadMembersEnabled: jest.fn(),
+                });
+                room = new Room(roomId, client, client.getSafeUserId());
+                client.getRoom.mockReturnValue(room);
+            });
+
+            afterEach(() => {
+                jest.restoreAllMocks();
+            });
+
+            const renderComponent = () => {
+                const context = new TestSdkContext();
+                context.client = client;
+                render(
+                    <SDKContext.Provider value={context}>
+                        <MemberList
+                            searchQuery=""
+                            onClose={jest.fn()}
+                            onSearchQueryChanged={jest.fn()}
+                            roomId={room.roomId}
+                        />
+                    </SDKContext.Provider>,
+                );
+            };
+
+            it("does not render invite button when current user is not a member", async () => {
+                renderComponent();
+                await flushPromises();
+
+                expect(screen.queryByText("Invite to this room")).not.toBeInTheDocument();
+            });
+
+            it("does not render invite button UI customisation hides invites", async () => {
+                mocked(shouldShowComponent).mockReturnValue(false);
+                renderComponent();
+                await flushPromises();
+
+                expect(screen.queryByText("Invite to this room")).not.toBeInTheDocument();
+            });
+
+            it("renders disabled invite button when current user is a member but does not have rights to invite", async () => {
+                jest.spyOn(room, "getMyMembership").mockReturnValue("join");
+                jest.spyOn(room, "canInvite").mockReturnValue(false);
+
+                renderComponent();
+                await flushPromises();
+
+                // button rendered but disabled
+                expect(screen.getByText("Invite to this room")).toBeDisabled();
+            });
+
+            it("renders enabled invite button when current user is a member and has rights to invite", async () => {
+                jest.spyOn(room, "getMyMembership").mockReturnValue("join");
+                jest.spyOn(room, "canInvite").mockReturnValue(true);
+
+                renderComponent();
+                await flushPromises();
+
+                expect(screen.getByText("Invite to this room")).not.toBeDisabled();
+            });
+
+            it("opens room inviter on button click", async () => {
+                jest.spyOn(defaultDispatcher, "dispatch");
+                jest.spyOn(room, "getMyMembership").mockReturnValue("join");
+                jest.spyOn(room, "canInvite").mockReturnValue(true);
+
+                renderComponent();
+                await flushPromises();
+
+                fireEvent.click(screen.getByText("Invite to this room"));
+
+                expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
+                    action: "view_invite",
+                    roomId,
+                });
+            });
+        });
     });
 });