diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/activity-indicator-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/activity-indicator-auto.png
new file mode 100644
index 0000000000..6ac546adbc
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/activity-indicator-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/invited-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/invited-auto.png
new file mode 100644
index 0000000000..cfd3f0f556
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/invited-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/mention-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/mention-auto.png
new file mode 100644
index 0000000000..bacce8176c
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/mention-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/mention-with-count-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/mention-with-count-auto.png
new file mode 100644
index 0000000000..773d314ec3
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/mention-with-count-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/muted-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/muted-auto.png
new file mode 100644
index 0000000000..d4dbca6e39
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/muted-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/muted-without-activity-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/muted-without-activity-auto.png
new file mode 100644
index 0000000000..d4dbca6e39
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/muted-without-activity-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/no-notification-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/no-notification-auto.png
new file mode 100644
index 0000000000..9f58a62407
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/no-notification-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/notification-with-count-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/notification-with-count-auto.png
new file mode 100644
index 0000000000..a146889ff0
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/notification-with-count-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/unsent-message-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/unsent-message-auto.png
new file mode 100644
index 0000000000..c2bcf320c5
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/unsent-message-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/video-call-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/video-call-auto.png
new file mode 100644
index 0000000000..9a6f8b5b35
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/video-call-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/video-call-without-activity-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/video-call-without-activity-auto.png
new file mode 100644
index 0000000000..9a6f8b5b35
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/video-call-without-activity-auto.png differ
diff --git a/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/voice-call-auto.png b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/voice-call-auto.png
new file mode 100644
index 0000000000..86f5cde837
Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx/voice-call-auto.png differ
diff --git a/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx
new file mode 100644
index 0000000000..db7ddf1f0a
--- /dev/null
+++ b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.stories.tsx
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2026 Element Creations 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 from "react";
+
+import type { Meta, StoryObj } from "@storybook/react-vite";
+import { NotificationDecoration, type NotificationDecorationProps } from "./NotificationDecoration";
+
+const defaultProps: NotificationDecorationProps = {
+ hasAnyNotificationOrActivity: false,
+ isUnsentMessage: false,
+ invited: false,
+ isMention: false,
+ isActivityNotification: false,
+ isNotification: false,
+ hasUnreadCount: false,
+ count: 0,
+ muted: false,
+};
+
+const meta = {
+ title: "Room List/NotificationDecoration",
+ component: NotificationDecoration,
+ tags: ["autodocs"],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ args: defaultProps,
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const NoNotification: Story = {};
+
+export const UnsentMessage: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ isUnsentMessage: true,
+ },
+};
+
+export const VideoCall: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ callType: "video",
+ },
+};
+
+export const VoiceCall: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ callType: "voice",
+ },
+};
+
+export const Invited: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ invited: true,
+ },
+};
+
+export const Mention: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ isMention: true,
+ },
+};
+
+export const MentionWithCount: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ isMention: true,
+ count: 5,
+ },
+};
+
+export const NotificationWithCount: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ isNotification: true,
+ count: 3,
+ },
+};
+
+export const ActivityIndicator: Story = {
+ args: {
+ hasAnyNotificationOrActivity: true,
+ isActivityNotification: true,
+ },
+};
+
+export const Muted: Story = {
+ args: {
+ muted: true,
+ },
+};
+
+export const MutedWithoutActivity: Story = {
+ args: {
+ hasAnyNotificationOrActivity: false,
+ muted: true,
+ },
+};
+
+export const VideoCallWithoutActivity: Story = {
+ args: {
+ hasAnyNotificationOrActivity: false,
+ callType: "video",
+ },
+};
diff --git a/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.test.tsx b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.test.tsx
new file mode 100644
index 0000000000..f79e092f4d
--- /dev/null
+++ b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.test.tsx
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2026 Element Creations 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 from "react";
+import { render } from "@test-utils";
+import { composeStories } from "@storybook/react-vite";
+import { describe, it, expect } from "vitest";
+
+import * as stories from "./NotificationDecoration.stories";
+
+const {
+ NoNotification,
+ UnsentMessage,
+ VideoCall,
+ VoiceCall,
+ Invited,
+ Mention,
+ MentionWithCount,
+ NotificationWithCount,
+ ActivityIndicator,
+ Muted,
+} = composeStories(stories);
+
+describe("", () => {
+ describe("snapshots", () => {
+ it("renders NoNotification story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders UnsentMessage story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders VideoCall story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders VoiceCall story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders Invited story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders Mention story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders MentionWithCount story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders NotificationWithCount story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders ActivityIndicator story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+
+ it("renders Muted story", () => {
+ const { container } = render();
+ expect(container).toMatchSnapshot();
+ });
+ });
+});
diff --git a/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.tsx b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.tsx
new file mode 100644
index 0000000000..03be962fbf
--- /dev/null
+++ b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/NotificationDecoration.tsx
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2026 Element Creations 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 from "react";
+import {
+ MentionIcon,
+ ErrorSolidIcon,
+ NotificationsOffSolidIcon,
+ VideoCallSolidIcon,
+ EmailSolidIcon,
+ VoiceCallSolidIcon,
+} from "@vector-im/compound-design-tokens/assets/web/icons";
+import { UnreadCounter, Unread } from "@vector-im/compound-web";
+
+import { Flex } from "../../../utils/Flex";
+
+/**
+ * Data representing the notification state for a room or item.
+ * Used in snapshots and passed to the NotificationDecoration component.
+ */
+export interface NotificationDecorationData {
+ /** Whether there is any notification or activity to display */
+ hasAnyNotificationOrActivity: boolean;
+ /** Whether there's an unsent message */
+ isUnsentMessage: boolean;
+ /** Whether the user is invited to the room */
+ invited: boolean;
+ /** Whether the notification is a mention */
+ isMention: boolean;
+ /** Whether there's activity (not a full notification) */
+ isActivityNotification: boolean;
+ /** Whether there's a notification (not just activity) */
+ isNotification: boolean;
+ /** Whether there are unread messages with a count */
+ hasUnreadCount: boolean;
+ /** Notification count */
+ count: number;
+ /** Whether notifications are muted */
+ muted: boolean;
+ /** Optional call type indicator */
+ callType?: "video" | "voice";
+}
+
+/**
+ * Props for the NotificationDecoration component.
+ */
+export interface NotificationDecorationProps extends NotificationDecorationData {}
+
+/**
+ * Renders notification badges and indicators for rooms/items
+ */
+export const NotificationDecoration: React.FC = ({
+ hasAnyNotificationOrActivity,
+ muted,
+ callType,
+ isUnsentMessage,
+ invited,
+ isMention,
+ isNotification,
+ isActivityNotification,
+ count,
+}) => {
+ // Don't render anything if there's nothing to show
+ if (!hasAnyNotificationOrActivity && !muted && !callType) {
+ return null;
+ }
+
+ return (
+
+ {isUnsentMessage && (
+
+ )}
+ {callType === "video" && (
+
+ )}
+ {callType === "voice" && (
+
+ )}
+ {invited && }
+ {isMention && }
+ {(isMention || isNotification) && }
+ {isActivityNotification && }
+ {muted && }
+
+ );
+};
diff --git a/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/__snapshots__/NotificationDecoration.test.tsx.snap b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/__snapshots__/NotificationDecoration.test.tsx.snap
new file mode 100644
index 0000000000..a7c7da94f4
--- /dev/null
+++ b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/__snapshots__/NotificationDecoration.test.tsx.snap
@@ -0,0 +1,242 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[` > snapshots > renders ActivityIndicator story 1`] = `
+
+`;
+
+exports[` > snapshots > renders Invited story 1`] = `
+
+`;
+
+exports[` > snapshots > renders Mention story 1`] = `
+
+`;
+
+exports[` > snapshots > renders MentionWithCount story 1`] = `
+
+`;
+
+exports[` > snapshots > renders Muted story 1`] = `
+
+`;
+
+exports[` > snapshots > renders NoNotification story 1`] = `
+
+`;
+
+exports[` > snapshots > renders NotificationWithCount story 1`] = `
+
+`;
+
+exports[` > snapshots > renders UnsentMessage story 1`] = `
+
+`;
+
+exports[` > snapshots > renders VideoCall story 1`] = `
+
+`;
+
+exports[` > snapshots > renders VoiceCall story 1`] = `
+
+`;
diff --git a/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/index.tsx b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/index.tsx
new file mode 100644
index 0000000000..42c7a3451f
--- /dev/null
+++ b/packages/shared-components/src/room-list/RoomListItem/NotificationDecoration/index.tsx
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2026 Element Creations 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.
+ */
+
+export { NotificationDecoration } from "./NotificationDecoration";
+export type { NotificationDecorationProps, NotificationDecorationData } from "./NotificationDecoration";