diff --git a/src/contents/ui/RoomTimelineView.qml b/src/contents/ui/RoomTimelineView.qml
--- a/src/contents/ui/RoomTimelineView.qml
+++ b/src/contents/ui/RoomTimelineView.qml
@@ -31,7 +31,7 @@
     prevEvent: index < timeline.count - 1 ? timeline.at(index + 1) : undefined
     event: timeline.at(index)
     width: ListView.view.width
-    isSelected: event.eventId === roomTimelineView.selectedEventId
+    isSelected: roomTimelineView.selectedEventId && event.eventId === roomTimelineView.selectedEventId
   }
 
   function goToEvent(eventId) {
diff --git a/src/tests/quick-tests/tst_RoomTimelineView.qml b/src/tests/quick-tests/tst_RoomTimelineView.qml
new file mode 100644
--- /dev/null
+++ b/src/tests/quick-tests/tst_RoomTimelineView.qml
@@ -0,0 +1,92 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import QtTest 1.0
+
+import moe.kazv.mxc.kazv 0.0 as MK
+import org.kde.kirigami 2.13 as Kirigami
+import '../../contents/ui' as Kazv
+import 'test-helpers.js' as Helpers
+import 'test-helpers' as TestHelpers
+
+Item {
+  id: item
+  width: 800
+  height: 600
+
+  property var mockHelper: TestHelpers.MockHelper {}
+
+  property var makeLocalEcho: (i) => ({
+    eventId: '',
+    sender: '',
+    type: 'm.room.message',
+    stateKey: '',
+    content: {
+      msgtype: 'm.text',
+      body: 'some body' + i,
+    },
+    encrypted: false,
+    isState: false,
+    unsignedData: {},
+    isLocalEcho: true,
+    isSending: true,
+    isFailed: false,
+    txnId: 'some-txn-id' + i,
+  })
+
+  property var makeTextEvent: (i) => ({
+    eventId: '$' + i,
+    sender: '@foo:tusooa.xyz',
+    type: 'm.room.message',
+    stateKey: '',
+    content: {
+      msgtype: 'm.text',
+      body: 'some body',
+    },
+    formattedTime: '4:06 P.M.',
+  })
+
+  Kazv.RoomTimelineView {
+    anchors.fill: parent
+    id: roomTimelineView
+    timeline: item.timeline
+  }
+
+  property var timeline: ListModel {
+    ListElement {}
+    ListElement {}
+
+    function at(index) {
+      if (index < 1) {
+        return makeLocalEcho(index);
+      } else {
+        return makeTextEvent(index);
+      }
+    }
+  }
+
+  TestCase {
+    id: roomTimelineViewTest
+    name: 'RoomTimelineViewTest'
+    when: windowShown
+
+    function test_selected() {
+      tryVerify(() => roomTimelineView.itemAtIndex(0));
+      tryVerify(() => roomTimelineView.itemAtIndex(1));
+
+      const localEcho = roomTimelineView.itemAtIndex(0);
+      verify(!localEcho.isSelected);
+
+      const sentMessage = roomTimelineView.itemAtIndex(1);
+      verify(!sentMessage.isSelected);
+
+      roomTimelineView.selectedEventId = '$1';
+      verify(sentMessage.isSelected);
+    }
+  }
+}