diff --git a/packages/text/src/markdown/__tests__/markdown.test.ts b/packages/text/src/markdown/__tests__/markdown.test.ts
index 2c47c91979..f7b25fd36e 100644
--- a/packages/text/src/markdown/__tests__/markdown.test.ts
+++ b/packages/text/src/markdown/__tests__/markdown.test.ts
@@ -395,6 +395,286 @@ Lorem ipsum dolor sit amet.
         }
       ]
     }
+  },
+  {
+    name: 'nested todos',
+    markdown: `# nested todos
+- [ ] todo
+  - [x] sub todo
+`,
+    markup: {
+      type: 'doc',
+      content: [
+        {
+          type: 'heading',
+          attrs: { level: 1 },
+          content: [
+            {
+              type: 'text',
+              text: 'nested todos',
+              marks: []
+            }
+          ]
+        },
+        {
+          type: 'todoList',
+          content: [
+            {
+              type: 'todoItem',
+              attrs: { checked: false },
+              content: [
+                {
+                  type: 'paragraph',
+                  content: [
+                    {
+                      type: 'text',
+                      text: 'todo',
+                      marks: []
+                    }
+                  ]
+                },
+                {
+                  type: 'todoList',
+                  content: [
+                    {
+                      type: 'todoItem',
+                      attrs: { checked: true },
+                      content: [
+                        {
+                          type: 'paragraph',
+                          content: [
+                            {
+                              type: 'text',
+                              text: 'sub todo',
+                              marks: []
+                            }
+                          ]
+                        }
+                      ]
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  },
+  {
+    name: 'nested lists',
+    markdown: `# nested lists
+- [ ] todo
+  - sub list item
+  - [x] sub todo
+- list item
+  - [x] sub todo
+  - sub list item
+`,
+    markup: {
+      type: 'doc',
+      content: [
+        {
+          type: 'heading',
+          attrs: { level: 1 },
+          content: [
+            {
+              type: 'text',
+              text: 'nested lists',
+              marks: []
+            }
+          ]
+        },
+        {
+          type: 'todoList',
+          content: [
+            {
+              type: 'todoItem',
+              attrs: { checked: false },
+              content: [
+                {
+                  type: 'paragraph',
+                  content: [
+                    {
+                      type: 'text',
+                      text: 'todo',
+                      marks: []
+                    }
+                  ]
+                },
+                {
+                  type: 'bulletList',
+                  content: [
+                    {
+                      type: 'listItem',
+                      content: [
+                        {
+                          type: 'paragraph',
+                          content: [
+                            {
+                              type: 'text',
+                              text: 'sub list item',
+                              marks: []
+                            }
+                          ]
+                        }
+                      ]
+                    }
+                  ]
+                },
+                {
+                  type: 'todoList',
+                  content: [
+                    {
+                      type: 'todoItem',
+                      attrs: { checked: true },
+                      content: [
+                        {
+                          type: 'paragraph',
+                          content: [
+                            {
+                              type: 'text',
+                              text: 'sub todo',
+                              marks: []
+                            }
+                          ]
+                        }
+                      ]
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        },
+        {
+          type: 'bulletList',
+          content: [
+            {
+              type: 'listItem',
+              content: [
+                {
+                  type: 'paragraph',
+                  content: [
+                    {
+                      type: 'text',
+                      text: 'list item',
+                      marks: []
+                    }
+                  ]
+                },
+                {
+                  type: 'todoList',
+                  content: [
+                    {
+                      type: 'todoItem',
+                      attrs: { checked: true },
+                      content: [
+                        {
+                          type: 'paragraph',
+                          content: [
+                            {
+                              type: 'text',
+                              text: 'sub todo',
+                              marks: []
+                            }
+                          ]
+                        }
+                      ]
+                    }
+                  ]
+                },
+                {
+                  type: 'bulletList',
+                  content: [
+                    {
+                      type: 'listItem',
+                      content: [
+                        {
+                          type: 'paragraph',
+                          content: [
+                            {
+                              type: 'text',
+                              text: 'sub list item',
+                              marks: []
+                            }
+                          ]
+                        }
+                      ]
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  },
+  {
+    name: 'nested todos',
+    markdown: `# nested todos
+- [ ] todo
+  - [x] sub todo
+`,
+    markup: {
+      type: 'doc',
+      content: [
+        {
+          type: 'heading',
+          attrs: { level: 1 },
+          content: [
+            {
+              type: 'text',
+              text: 'nested todos',
+              marks: []
+            }
+          ]
+        },
+        {
+          type: 'todoList',
+          content: [
+            {
+              type: 'todoItem',
+              attrs: { checked: false },
+              content: [
+                {
+                  type: 'paragraph',
+                  content: [
+                    {
+                      type: 'text',
+                      text: 'todo',
+                      marks: []
+                    }
+                  ]
+                },
+                {
+                  type: 'todoList',
+                  content: [
+                    {
+                      type: 'todoItem',
+                      attrs: { checked: true },
+                      content: [
+                        {
+                          type: 'paragraph',
+                          content: [
+                            {
+                              type: 'text',
+                              text: 'sub todo',
+                              marks: []
+                            }
+                          ]
+                        }
+                      ]
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
   }
 ]
 
diff --git a/packages/text/src/markdown/parser.ts b/packages/text/src/markdown/parser.ts
index e4c2f88c60..647211cecb 100644
--- a/packages/text/src/markdown/parser.ts
+++ b/packages/text/src/markdown/parser.ts
@@ -621,6 +621,7 @@ export class MarkdownParser {
 
   listRule: RuleCore = (state: TaskListStateCore): boolean => {
     const tokens = state.tokens
+    const states: Array<{ closeIdx: number, lastItemIdx: number }> = []
 
     // step #1 - convert list items to todo items
     for (let open = 0; open < tokens.length; open++) {
@@ -630,32 +631,36 @@ export class MarkdownParser {
     }
 
     // step #2 - convert lists to proper type
-    let closeIdx = -1
-    let lastItemIdx = -1
+    // listCloseIdx and itemCloseIdx tracks position of the list and item close tokens
+    // because we insert items into the list, the variables keep the position from the
+    // end of the list so we don't have to count inserts
+    let listCloseIdx = -1
+    let itemCloseIdx = -1
+
     for (let i = tokens.length - 1; i >= 0; i--) {
       if (tokens[i].type === 'bullet_list_close') {
-        closeIdx = i
-        lastItemIdx = -1
+        states.push({ closeIdx: listCloseIdx, lastItemIdx: itemCloseIdx })
+        listCloseIdx = tokens.length - i
+        itemCloseIdx = -1
       } else if (tokens[i].type === 'list_item_close' || tokens[i].type === 'todo_item_close') {
         // when found item close token of different type, split the list
-        if (lastItemIdx === -1) {
-          lastItemIdx = i
-        } else if (tokens[i].type !== tokens[lastItemIdx].type) {
+        if (itemCloseIdx === -1) {
+          itemCloseIdx = tokens.length - i
+        } else if (tokens[i].type !== tokens[tokens.length - itemCloseIdx].type) {
           tokens.splice(i + 1, 0, new state.Token('bullet_list_open', 'ul', 1))
           tokens.splice(i + 1, 0, new state.Token('bullet_list_close', 'ul', -1))
-          convertTodoList(tokens, i + 2, closeIdx + 2, lastItemIdx + 2)
-          closeIdx = i + 1
-          lastItemIdx = i
+          convertTodoList(tokens, i + 2, tokens.length - listCloseIdx, tokens.length - itemCloseIdx)
+          listCloseIdx = tokens.length - i - 1
+          itemCloseIdx = tokens.length - i
         }
-      } else if (tokens[i].type === 'bullet_list_open' && tokens[i].level === tokens[closeIdx].level) {
-        // when found list open token of the same level, decide what to do
-        if (lastItemIdx !== -1) {
-          convertTodoList(tokens, i, closeIdx, lastItemIdx)
+      } else if (tokens[i].type === 'bullet_list_open') {
+        if (itemCloseIdx !== -1) {
+          convertTodoList(tokens, i, tokens.length - listCloseIdx, tokens.length - itemCloseIdx)
         }
 
-        // Reset closeIdx and lastItemIdx for the next list
-        closeIdx = -1
-        lastItemIdx = -1
+        const prevState = states.pop() ?? { closeIdx: -1, lastItemIdx: -1 }
+        listCloseIdx = prevState.closeIdx
+        itemCloseIdx = prevState.lastItemIdx
       }
     }