diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5b511f7..0fb8e1d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.14)
 
-project(scratchcpp-render VERSION 0.7.2 LANGUAGES CXX)
+project(scratchcpp-render VERSION 0.7.3 LANGUAGES CXX)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 set(CMAKE_AUTOUIC ON)
diff --git a/libscratchcpp b/libscratchcpp
index 4f55c6f..f4f3fd0 160000
--- a/libscratchcpp
+++ b/libscratchcpp
@@ -1 +1 @@
-Subproject commit 4f55c6f348e649214ccad769f27bbaba1e8081b1
+Subproject commit f4f3fd0e15a22b58e3eabbcbd69c4da68484e318
diff --git a/src/internal/ListMonitor.qml b/src/internal/ListMonitor.qml
index 5195e7e..8fe6875 100644
--- a/src/internal/ListMonitor.qml
+++ b/src/internal/ListMonitor.qml
@@ -77,6 +77,7 @@ Rectangle {
     ListView {
         property real oldContentY
         readonly property int scrollBarWidth: 15
+        property int itemHeight: 24 // NOTE: Hard-coded value
 
         id: listView
         anchors.left: parent.left
@@ -87,6 +88,25 @@ Rectangle {
         clip: true
         model: root.model ? root.model.listModel : null
         boundsBehavior: Flickable.StopAtBounds
+        onContentXChanged: updateVisibleIndexRange()
+        onContentYChanged: updateVisibleIndexRange()
+        onCountChanged: updateVisibleIndexRange()
+
+        function getVisibleIndexRange() {
+            if(count === 0)
+                return [0, 0];
+
+            let y1 = listView.contentY - itemHeight;
+            let y2 = listView.contentY + listView.height;
+            return [Math.max(0, Math.ceil(y1 / itemHeight)),
+                    Math.min(Math.floor(y2 / itemHeight), count - 1)];
+        }
+
+        function updateVisibleIndexRange() {
+            let range = getVisibleIndexRange();
+            root.model.minIndex = range[0];
+            root.model.maxIndex = range[1];
+        }
 
         ScrollBar.vertical: ScrollBar {
             id: scrollBar
diff --git a/src/listmonitorlistmodel.cpp b/src/listmonitorlistmodel.cpp
index a055bcc..e7410eb 100644
--- a/src/listmonitorlistmodel.cpp
+++ b/src/listmonitorlistmodel.cpp
@@ -11,11 +11,14 @@ ListMonitorListModel::ListMonitorListModel(QObject *parent) :
 {
 }
 
-void ListMonitorListModel::setList(libscratchcpp::List *list)
+void ListMonitorListModel::setList(libscratchcpp::List *list, size_t minVisibleIndex, size_t maxVisibleIndex)
 {
     if (!list)
         return;
 
+    m_minIndex = minVisibleIndex;
+    m_maxIndex = maxVisibleIndex;
+
     // Initial load
     if (m_list != list) {
         beginResetModel();
@@ -25,10 +28,8 @@ void ListMonitorListModel::setList(libscratchcpp::List *list)
         return;
     }
 
-    // Notify about changed items
-    int count = std::min(m_oldRowCount, static_cast<int>(m_list->size()));
-
-    for (int i = 0; i < count; i++)
+    // Update visible items
+    for (size_t i = minVisibleIndex; i <= maxVisibleIndex; i++)
         emit dataChanged(index(i), index(i));
 
     // Notify about new items (at the end of the list)
@@ -54,8 +55,8 @@ int ListMonitorListModel::rowCount(const QModelIndex &parent) const
 
 QVariant ListMonitorListModel::data(const QModelIndex &index, int role) const
 {
-    if (!m_list || index.row() < 0 || index.row() >= m_list->size())
-        return QVariant();
+    if (!m_list || index.row() < m_minIndex || index.row() > m_maxIndex)
+        return "";
 
     return QString::fromStdString(libscratchcpp::Value((*m_list)[index.row()]).toString());
 }
diff --git a/src/listmonitorlistmodel.h b/src/listmonitorlistmodel.h
index cb0a8ce..26359a5 100644
--- a/src/listmonitorlistmodel.h
+++ b/src/listmonitorlistmodel.h
@@ -19,7 +19,7 @@ class ListMonitorListModel : public QAbstractListModel
     public:
         explicit ListMonitorListModel(QObject *parent = nullptr);
 
-        void setList(libscratchcpp::List *list);
+        void setList(libscratchcpp::List *list, size_t minVisibleIndex, size_t maxVisibleIndex);
 
         int rowCount(const QModelIndex &parent) const override;
         QVariant data(const QModelIndex &index, int role) const override;
@@ -27,7 +27,9 @@ class ListMonitorListModel : public QAbstractListModel
 
     private:
         libscratchcpp::List *m_list = nullptr;
-        int m_oldRowCount = 0;
+        size_t m_oldRowCount = 0;
+        size_t m_minIndex = 0;
+        size_t m_maxIndex = 0;
 };
 
 } // namespace scratchcpprender
diff --git a/src/listmonitormodel.cpp b/src/listmonitormodel.cpp
index 2182303..b88b3e9 100644
--- a/src/listmonitormodel.cpp
+++ b/src/listmonitormodel.cpp
@@ -23,7 +23,7 @@ void ListMonitorModel::onValueChanged(const libscratchcpp::VirtualMachine *vm)
     if (vm->registerCount() == 1) {
         long index = vm->getInput(0, 1)->toLong();
         libscratchcpp::List *list = vm->lists()[index];
-        m_listModel->setList(list);
+        m_listModel->setList(list, m_minIndex, m_maxIndex);
     }
 }
 
@@ -36,3 +36,31 @@ ListMonitorListModel *ListMonitorModel::listModel() const
 {
     return m_listModel;
 }
+
+size_t ListMonitorModel::minIndex() const
+{
+    return m_minIndex;
+}
+
+void ListMonitorModel::setMinIndex(size_t newMinIndex)
+{
+    if (m_minIndex == newMinIndex)
+        return;
+
+    m_minIndex = newMinIndex;
+    emit minIndexChanged();
+}
+
+size_t ListMonitorModel::maxIndex() const
+{
+    return m_maxIndex;
+}
+
+void ListMonitorModel::setMaxIndex(size_t newMaxIndex)
+{
+    if (m_maxIndex == newMaxIndex)
+        return;
+
+    m_maxIndex = newMaxIndex;
+    emit maxIndexChanged();
+}
diff --git a/src/listmonitormodel.h b/src/listmonitormodel.h
index 4034e03..acda897 100644
--- a/src/listmonitormodel.h
+++ b/src/listmonitormodel.h
@@ -18,6 +18,8 @@ class ListMonitorModel : public MonitorModel
         Q_OBJECT
         QML_ELEMENT
         Q_PROPERTY(ListMonitorListModel *listModel READ listModel NOTIFY listModelChanged)
+        Q_PROPERTY(size_t minIndex READ minIndex WRITE setMinIndex NOTIFY minIndexChanged FINAL);
+        Q_PROPERTY(size_t maxIndex READ maxIndex WRITE setMaxIndex NOTIFY maxIndexChanged FINAL)
 
     public:
         ListMonitorModel(QObject *parent = nullptr);
@@ -29,12 +31,22 @@ class ListMonitorModel : public MonitorModel
 
         ListMonitorListModel *listModel() const;
 
+        size_t minIndex() const;
+        void setMinIndex(size_t newMinIndex);
+
+        size_t maxIndex() const;
+        void setMaxIndex(size_t newMaxIndex);
+
     signals:
         void colorChanged();
         void listModelChanged();
+        void minIndexChanged();
+        void maxIndexChanged();
 
     private:
         ListMonitorListModel *m_listModel = nullptr;
+        size_t m_minIndex = 0;
+        size_t m_maxIndex = 0;
 };
 
 } // namespace scratchcpprender
diff --git a/test/monitor_models/listmonitorlistmodel_test.cpp b/test/monitor_models/listmonitorlistmodel_test.cpp
index 42c1539..544f4f0 100644
--- a/test/monitor_models/listmonitorlistmodel_test.cpp
+++ b/test/monitor_models/listmonitorlistmodel_test.cpp
@@ -28,7 +28,9 @@ TEST(ListMonitorListModelTest, LoadData)
     List list1("", "");
     list1.append(1);
     list1.append(2);
-    model.setList(&list1);
+    list1.append(3);
+    list1.append(4);
+    model.setList(&list1, 0, 3);
     ASSERT_TRUE(dataChangedSpy.empty());
     ASSERT_EQ(aboutToResetSpy.count(), 1);
     ASSERT_EQ(resetSpy.count(), 1);
@@ -37,8 +39,17 @@ TEST(ListMonitorListModelTest, LoadData)
     ASSERT_TRUE(aboutToRemoveSpy.empty());
     ASSERT_TRUE(removeSpy.empty());
 
-    model.setList(&list1);
-    ASSERT_EQ(dataChangedSpy.count(), 2);
+    model.setList(&list1, 0, 3);
+    ASSERT_EQ(dataChangedSpy.count(), 4);
+    ASSERT_EQ(aboutToResetSpy.count(), 1);
+    ASSERT_EQ(resetSpy.count(), 1);
+    ASSERT_TRUE(aboutToInsertSpy.empty());
+    ASSERT_TRUE(insertSpy.empty());
+    ASSERT_TRUE(aboutToRemoveSpy.empty());
+    ASSERT_TRUE(removeSpy.empty());
+
+    model.setList(&list1, 1, 3);
+    ASSERT_EQ(dataChangedSpy.count(), 7);
     ASSERT_EQ(aboutToResetSpy.count(), 1);
     ASSERT_EQ(resetSpy.count(), 1);
     ASSERT_TRUE(aboutToInsertSpy.empty());
@@ -65,8 +76,8 @@ TEST(ListMonitorListModelTest, LoadData)
     ASSERT_TRUE(args.at(2).toList().isEmpty());
 
     List list2("", "");
-    model.setList(&list2);
-    ASSERT_EQ(dataChangedSpy.count(), 2);
+    model.setList(&list2, 0, 3);
+    ASSERT_EQ(dataChangedSpy.count(), 7);
     ASSERT_EQ(aboutToResetSpy.count(), 2);
     ASSERT_EQ(resetSpy.count(), 2);
     ASSERT_TRUE(aboutToInsertSpy.empty());
@@ -89,7 +100,7 @@ TEST(ListMonitorListModelTest, AddRows)
     List list1("", "");
     list1.append(1);
     list1.append(2);
-    model.setList(&list1);
+    model.setList(&list1, 0, 1);
     ASSERT_TRUE(dataChangedSpy.empty());
     ASSERT_EQ(aboutToResetSpy.count(), 1);
     ASSERT_EQ(resetSpy.count(), 1);
@@ -101,7 +112,7 @@ TEST(ListMonitorListModelTest, AddRows)
     list1.append(9);
     list1.append(8);
     list1.append(7);
-    model.setList(&list1);
+    model.setList(&list1, 2, 3);
     ASSERT_EQ(dataChangedSpy.count(), 2);
     ASSERT_EQ(aboutToResetSpy.count(), 1);
     ASSERT_EQ(resetSpy.count(), 1);
@@ -113,18 +124,18 @@ TEST(ListMonitorListModelTest, AddRows)
     auto args = dataChangedSpy.at(0);
     QModelIndex arg1 = args.at(0).value<QModelIndex>();
     QModelIndex arg2 = args.at(1).value<QModelIndex>();
-    ASSERT_EQ(arg1.row(), 0);
+    ASSERT_EQ(arg1.row(), 2);
     ASSERT_EQ(arg1.column(), 0);
-    ASSERT_EQ(arg2.row(), 0);
+    ASSERT_EQ(arg2.row(), 2);
     ASSERT_EQ(arg2.column(), 0);
     ASSERT_TRUE(args.at(2).toList().isEmpty());
 
     args = dataChangedSpy.at(1);
     arg1 = args.at(0).value<QModelIndex>();
     arg2 = args.at(1).value<QModelIndex>();
-    ASSERT_EQ(arg1.row(), 1);
+    ASSERT_EQ(arg1.row(), 3);
     ASSERT_EQ(arg1.column(), 0);
-    ASSERT_EQ(arg2.row(), 1);
+    ASSERT_EQ(arg2.row(), 3);
     ASSERT_EQ(arg2.column(), 0);
     ASSERT_TRUE(args.at(2).toList().isEmpty());
 
@@ -150,7 +161,7 @@ TEST(ListMonitorListModelTest, RemoveRows)
     list1.append(1);
     list1.append(2);
     list1.append(3);
-    model.setList(&list1);
+    model.setList(&list1, 0, 2);
     ASSERT_TRUE(dataChangedSpy.empty());
     ASSERT_EQ(aboutToResetSpy.count(), 1);
     ASSERT_EQ(resetSpy.count(), 1);
@@ -161,7 +172,7 @@ TEST(ListMonitorListModelTest, RemoveRows)
 
     list1.removeAt(2);
     list1.removeAt(0);
-    model.setList(&list1);
+    model.setList(&list1, 0, 0);
     ASSERT_EQ(dataChangedSpy.count(), 1);
     ASSERT_EQ(aboutToResetSpy.count(), 1);
     ASSERT_EQ(resetSpy.count(), 1);
@@ -193,7 +204,7 @@ TEST(ListMonitorListModelTest, RowCount)
     list.append(1);
     list.append(2);
     list.append(3);
-    model.setList(&list);
+    model.setList(&list, 0, 2);
     ASSERT_EQ(model.rowCount(QModelIndex()), list.size());
 }
 
@@ -204,7 +215,7 @@ TEST(ListMonitorListModelTest, Data)
     list.append(1);
     list.append(2);
     list.append(3);
-    model.setList(&list);
+    model.setList(&list, 0, 2);
     ASSERT_EQ(model.data(model.index(0), 0).toString(), "1");
     ASSERT_EQ(model.data(model.index(1), 0).toString(), "2");
     ASSERT_EQ(model.data(model.index(2), 0).toString(), "3");
diff --git a/test/monitor_models/listmonitormodel_test.cpp b/test/monitor_models/listmonitormodel_test.cpp
index 1b00f00..6f9db75 100644
--- a/test/monitor_models/listmonitormodel_test.cpp
+++ b/test/monitor_models/listmonitormodel_test.cpp
@@ -28,6 +28,7 @@ TEST(ListMonitorModelTest, OnValueChanged)
 {
     ListMonitorModel model;
     ListMonitorListModel *listModel = model.listModel();
+    QSignalSpy dataChangedSpy(listModel, &ListMonitorListModel::dataChanged);
     VirtualMachine vm;
 
     List list1("", "");
@@ -57,6 +58,23 @@ TEST(ListMonitorModelTest, OnValueChanged)
     model.onValueChanged(&vm);
     ASSERT_EQ(listModel->rowCount(QModelIndex()), 3);
 
+    vm.reset();
+    vm.addReturnValue(2);
+    model.setMinIndex(0);
+    model.setMaxIndex(3);
+    model.onValueChanged(&vm);
+    ASSERT_EQ(listModel->rowCount(QModelIndex()), 3);
+    ASSERT_EQ(dataChangedSpy.count(), 4);
+
+    dataChangedSpy.clear();
+    vm.reset();
+    vm.addReturnValue(2);
+    model.setMinIndex(1);
+    model.setMaxIndex(2);
+    model.onValueChanged(&vm);
+    ASSERT_EQ(listModel->rowCount(QModelIndex()), 3);
+    ASSERT_EQ(dataChangedSpy.count(), 2);
+
     vm.reset();
     vm.addReturnValue(0);
     model.onValueChanged(&vm);
@@ -68,3 +86,21 @@ TEST(ListMonitorModelTest, Type)
     ListMonitorModel model;
     ASSERT_EQ(model.type(), MonitorModel::Type::List);
 }
+
+TEST(ListMonitorModelTest, MinIndex)
+{
+    ListMonitorModel model;
+    ASSERT_EQ(model.minIndex(), 0);
+
+    model.setMinIndex(2);
+    ASSERT_EQ(model.minIndex(), 2);
+}
+
+TEST(ListMonitorModelTest, MaxIndex)
+{
+    ListMonitorModel model;
+    ASSERT_EQ(model.maxIndex(), 0);
+
+    model.setMaxIndex(17);
+    ASSERT_EQ(model.maxIndex(), 17);
+}
