diff --git a/packages/slidev/node/syntax/index.ts b/packages/slidev/node/syntax/index.ts
index b3089c6035..41b083030c 100644
--- a/packages/slidev/node/syntax/index.ts
+++ b/packages/slidev/node/syntax/index.ts
@@ -2,7 +2,6 @@ import type { CodeblockTransformer, ResolvedSlidevOptions } from '@slidev/types'
import type MagicString from 'magic-string'
import type MarkdownExit from 'markdown-exit'
import MarkdownItComark from '@comark/markdown-it'
-import { taskLists as MarkdownItTaskList } from '@hedgedoc/markdown-it-plugins'
// @ts-expect-error missing types
import MarkdownItFootnote from 'markdown-it-footnote'
import MarkdownItGitHubAlerts from 'markdown-it-github-alerts'
@@ -15,6 +14,7 @@ import MarkdownItStyleScoped from './scoped'
import MarkdownItShiki from './shiki'
import MarkdownItSlotSugar from './slot-sugar'
import MarkdownItSnippet from './snippet'
+import MarkdownItTaskList from './task-list'
export async function useMarkdownItPlugins(
md: MarkdownExit,
diff --git a/packages/slidev/node/syntax/task-list.test.ts b/packages/slidev/node/syntax/task-list.test.ts
new file mode 100644
index 0000000000..5dcc5c4033
--- /dev/null
+++ b/packages/slidev/node/syntax/task-list.test.ts
@@ -0,0 +1,17 @@
+import MarkdownItComark from '@comark/markdown-it'
+import MarkdownExit from 'markdown-exit'
+import { expect, it } from 'vitest'
+import MarkdownItTaskList from './task-list'
+
+it('does not render task list markers when comark is enabled', async () => {
+ const md = MarkdownExit({ html: true })
+ md.use(MarkdownItTaskList, { enabled: true, lineNumber: true, label: true })
+ md.use(MarkdownItComark)
+
+ const result = await md.renderAsync('- [x] test\n- [ ] test')
+
+ expect(result).toContain('')
+ expect(result).toContain('')
+ expect(result).not.toContain('x')
+ expect(result).not.toContain(' ')
+})
diff --git a/packages/slidev/node/syntax/task-list.ts b/packages/slidev/node/syntax/task-list.ts
new file mode 100644
index 0000000000..112446be04
--- /dev/null
+++ b/packages/slidev/node/syntax/task-list.ts
@@ -0,0 +1,51 @@
+import type { MarkdownExit } from 'markdown-exit'
+import { taskLists as HedgeDocMarkdownItTaskList } from '@hedgedoc/markdown-it-plugins'
+
+type TaskListOptions = Parameters[1]
+type Token = ReturnType[number]
+
+const TASK_LIST_MARKER_RE = /^\[[ x]\]\s/i
+const COMARK_TASK_LIST_MARKER_RE = /^[ x]$/i
+
+export default function MarkdownItTaskList(md: MarkdownExit, options?: TaskListOptions) {
+ md.use(HedgeDocMarkdownItTaskList, options)
+
+ md.core.ruler.after('task-lists', 'slidev_task_list_comark', (state) => {
+ for (const token of state.tokens) {
+ if (token.type !== 'inline' || !TASK_LIST_MARKER_RE.test(token.content))
+ continue
+
+ removeLeadingComarkMarker(token.children)
+ }
+ })
+}
+
+function removeLeadingComarkMarker(children?: Token[]) {
+ if (!children?.length)
+ return
+
+ let index = children.findIndex(child => child.type === 'taskListItemCheckbox')
+ if (index < 0)
+ return
+
+ index += 1
+ if (children[index]?.type === 'taskListItemLabel_open')
+ index += 1
+
+ if (
+ children[index]?.type !== 'mdc_inline_span'
+ || children[index]?.nesting !== 1
+ || children[index + 1]?.type !== 'text'
+ || !COMARK_TASK_LIST_MARKER_RE.test(children[index + 1].content)
+ || children[index + 2]?.type !== 'mdc_inline_span'
+ || children[index + 2]?.nesting !== -1
+ ) {
+ return
+ }
+
+ children.splice(index, 3)
+
+ const next = children[index]
+ if (next?.type === 'text' && next.content.startsWith(' '))
+ next.content = next.content.slice(1)
+}