diff --git a/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts b/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts
new file mode 100644
index 0000000000..59f5a2fcab
--- /dev/null
+++ b/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import { expect, test } from "../../../element-web-test";
+import type { Page } from "@playwright/test";
+
+test.describe("Room list filters and sort", () => {
+ test.use({
+ displayName: "Alice",
+ botCreateOpts: {
+ displayName: "BotBob",
+ autoAcceptInvites: true,
+ },
+ labsFlags: ["feature_new_room_list"],
+ });
+
+ /**
+ * Get the room list
+ * @param page
+ */
+ function getRoomList(page: Page) {
+ return page.getByTestId("room-list");
+ }
+
+ function getPrimaryFilters(page: Page) {
+ return page.getByRole("listbox", { name: "Room list filters" });
+ }
+
+ test.beforeEach(async ({ page, app, bot, user }) => {
+ // The notification toast is displayed above the search section
+ await app.closeNotificationToast();
+
+ await app.client.createRoom({ name: "empty room" });
+
+ const unReadDmId = await bot.createRoom({
+ name: "unread dm",
+ invite: [user.userId],
+ is_direct: true,
+ });
+ await bot.sendMessage(unReadDmId, "I am a robot. Beep.");
+
+ const unReadRoomId = await app.client.createRoom({ name: "unread room" });
+ await app.client.inviteUser(unReadRoomId, bot.credentials.userId);
+ await bot.joinRoom(unReadRoomId);
+ await bot.sendMessage(unReadRoomId, "I am a robot. Beep.");
+
+ const favouriteId = await app.client.createRoom({ name: "favourite room" });
+ await app.client.evaluate(async (client, favouriteId) => {
+ await client.setRoomTag(favouriteId, "m.favourite", { order: 0.5 });
+ }, favouriteId);
+ });
+
+ test("should filter the list (with primary filters)", { tag: "@screenshot" }, async ({ page, app, user }) => {
+ const roomList = getRoomList(page);
+ const primaryFilters = getPrimaryFilters(page);
+
+ const allFilters = await primaryFilters.locator("option").all();
+ for (const filter of allFilters) {
+ expect(await filter.getAttribute("aria-selected")).toBe("false");
+ }
+ await expect(primaryFilters).toMatchScreenshot("unselected-primary-filters.png");
+
+ await primaryFilters.getByRole("option", { name: "Unread" }).click();
+ // only one room should be visible
+ await expect(roomList.getByRole("gridcell", { name: "unread dm" })).toBeVisible();
+ await expect(roomList.getByRole("gridcell", { name: "unread room" })).toBeVisible();
+ expect(await roomList.locator("role=gridcell").count()).toBe(2);
+ await expect(primaryFilters).toMatchScreenshot("unread-primary-filters.png");
+
+ await primaryFilters.getByRole("option", { name: "Favourite" }).click();
+ await expect(roomList.getByRole("gridcell", { name: "favourite room" })).toBeVisible();
+ expect(await roomList.locator("role=gridcell").count()).toBe(1);
+
+ await primaryFilters.getByRole("option", { name: "People" }).click();
+ await expect(roomList.getByRole("gridcell", { name: "unread dm" })).toBeVisible();
+ expect(await roomList.locator("role=gridcell").count()).toBe(1);
+
+ await primaryFilters.getByRole("option", { name: "Rooms" }).click();
+ await expect(roomList.getByRole("gridcell", { name: "unread room" })).toBeVisible();
+ await expect(roomList.getByRole("gridcell", { name: "favourite room" })).toBeVisible();
+ await expect(roomList.getByRole("gridcell", { name: "empty room" })).toBeVisible();
+ expect(await roomList.locator("role=gridcell").count()).toBe(3);
+ });
+});
diff --git a/playwright/snapshots/left-panel/room-list-panel/room-list-filter-sort.spec.ts/unread-primary-filters-linux.png b/playwright/snapshots/left-panel/room-list-panel/room-list-filter-sort.spec.ts/unread-primary-filters-linux.png
new file mode 100644
index 0000000000..8c056bc754
Binary files /dev/null and b/playwright/snapshots/left-panel/room-list-panel/room-list-filter-sort.spec.ts/unread-primary-filters-linux.png differ
diff --git a/playwright/snapshots/left-panel/room-list-panel/room-list-filter-sort.spec.ts/unselected-primary-filters-linux.png b/playwright/snapshots/left-panel/room-list-panel/room-list-filter-sort.spec.ts/unselected-primary-filters-linux.png
new file mode 100644
index 0000000000..06314b5213
Binary files /dev/null and b/playwright/snapshots/left-panel/room-list-panel/room-list-filter-sort.spec.ts/unselected-primary-filters-linux.png differ
diff --git a/playwright/snapshots/left-panel/room-list-panel/room-list-panel.spec.ts/room-list-panel-linux.png b/playwright/snapshots/left-panel/room-list-panel/room-list-panel.spec.ts/room-list-panel-linux.png
index 1ebfde5ea7..cba5fa86d4 100644
Binary files a/playwright/snapshots/left-panel/room-list-panel/room-list-panel.spec.ts/room-list-panel-linux.png and b/playwright/snapshots/left-panel/room-list-panel/room-list-panel.spec.ts/room-list-panel-linux.png differ
diff --git a/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-linux.png b/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-linux.png
index f9275dd211..5d88f45aa5 100644
Binary files a/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-linux.png and b/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-linux.png differ
diff --git a/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-scrolled-linux.png b/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-scrolled-linux.png
index 79c9254f0a..157b0ce156 100644
Binary files a/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-scrolled-linux.png and b/playwright/snapshots/left-panel/room-list-panel/room-list.spec.ts/room-list-scrolled-linux.png differ
diff --git a/res/css/_components.pcss b/res/css/_components.pcss
index 8501ed7bd1..a8536a2d4d 100644
--- a/res/css/_components.pcss
+++ b/res/css/_components.pcss
@@ -273,6 +273,7 @@
@import "./views/rooms/RoomListPanel/_RoomListCell.pcss";
@import "./views/rooms/RoomListPanel/_RoomListHeaderView.pcss";
@import "./views/rooms/RoomListPanel/_RoomListPanel.pcss";
+@import "./views/rooms/RoomListPanel/_RoomListPrimaryFilters.pcss";
@import "./views/rooms/RoomListPanel/_RoomListSearch.pcss";
@import "./views/rooms/_AppsDrawer.pcss";
@import "./views/rooms/_Autocomplete.pcss";
diff --git a/res/css/views/rooms/RoomListPanel/_RoomListPrimaryFilters.pcss b/res/css/views/rooms/RoomListPanel/_RoomListPrimaryFilters.pcss
new file mode 100644
index 0000000000..ac85782bbd
--- /dev/null
+++ b/res/css/views/rooms/RoomListPanel/_RoomListPrimaryFilters.pcss
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+.mx_RoomListPrimaryFilters {
+ margin: unset;
+ list-style-type: none;
+ padding: var(--cpd-space-2x) var(--cpd-space-3x);
+}
diff --git a/src/components/views/rooms/RoomListPanel/RoomListPrimaryFilters.tsx b/src/components/views/rooms/RoomListPanel/RoomListPrimaryFilters.tsx
new file mode 100644
index 0000000000..ebf972d361
--- /dev/null
+++ b/src/components/views/rooms/RoomListPanel/RoomListPrimaryFilters.tsx
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import React, { type JSX } from "react";
+import { ChatFilter } from "@vector-im/compound-web";
+
+import type { RoomListViewState } from "../../../viewmodels/roomlist/RoomListViewModel";
+import { Flex } from "../../../utils/Flex";
+import { _t } from "../../../../languageHandler";
+
+interface RoomListPrimaryFiltersProps {
+ /**
+ * The view model for the room list
+ */
+ vm: RoomListViewState;
+}
+
+/**
+ * The primary filters for the room list
+ */
+export function RoomListPrimaryFilters({ vm }: RoomListPrimaryFiltersProps): JSX.Element {
+ return (
+