diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,14 @@
 
 `pandoc-lua-marshal` uses [PVP Versioning][].
 
-## 0.2.3
+## 0.2.5
+
+Released 2024-03-04.
+
+-   The `clone` method on *Blocks* and *Inlines* elements now
+    creates deep copies of the lists.
+
+## 0.2.4
 
 Released 2024-01-19.
 
diff --git a/pandoc-lua-marshal.cabal b/pandoc-lua-marshal.cabal
--- a/pandoc-lua-marshal.cabal
+++ b/pandoc-lua-marshal.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.4
 name:                pandoc-lua-marshal
-version:             0.2.4
+version:             0.2.5
 synopsis:            Use pandoc types in Lua
 description:         This package provides functions to marshal and unmarshal
                      pandoc document types to and from Lua.
diff --git a/src/Text/Pandoc/Lua/Marshal/Block.hs b/src/Text/Pandoc/Lua/Marshal/Block.hs
--- a/src/Text/Pandoc/Lua/Marshal/Block.hs
+++ b/src/Text/Pandoc/Lua/Marshal/Block.hs
@@ -86,6 +86,13 @@
       =#> functionResult pushBlocks "Blocks" "modified list"
     rawset (nth 3)
 
+    pushName "clone"
+    pushDocumentedFunction $ lambda
+      ### return
+      <#> parameter peekBlocksFuzzy "Blocks" "self" ""
+      =#> functionResult pushBlocks "Blocks" "deep copy"
+    rawset (nth 3)
+
     pushName "__tostring"
     pushDocumentedFunction $ lambda
       ### liftPure show
diff --git a/src/Text/Pandoc/Lua/Marshal/Inline.hs b/src/Text/Pandoc/Lua/Marshal/Inline.hs
--- a/src/Text/Pandoc/Lua/Marshal/Inline.hs
+++ b/src/Text/Pandoc/Lua/Marshal/Inline.hs
@@ -79,6 +79,13 @@
       =#> functionResult pushInlines "Blocks" "modified list"
     rawset (nth 3)
 
+    pushName "clone"
+    pushDocumentedFunction $ lambda
+      ### return
+      <#> parameter peekInlinesFuzzy "Inlines" "self" ""
+      =#> functionResult pushInlines "Inlines" "deep copy"
+    rawset (nth 3)
+
     pushName "__tostring"
     pushDocumentedFunction $ lambda
       ### liftPure show
diff --git a/test/test-block.lua b/test/test-block.lua
--- a/test/test-block.lua
+++ b/test/test-block.lua
@@ -409,6 +409,22 @@
         )
       end)
     },
+    group 'clone' {
+      test('function exists', function ()
+        assert.are_equal(type(Blocks({}).clone), 'function')
+      end),
+      test('clones the list', function ()
+        local blks = Blocks{Para('One'), CodeBlock 'two'}
+        assert.are_same(blks, blks:clone())
+      end),
+      test('deep-clones the list', function ()
+        local blks = Blocks{Para('one'), CodeBlock 'two'}
+        local copy = blks:clone()
+        copy[1].content[1].text = 'heh'
+        assert.are_same(Blocks{Para('heh'), CodeBlock 'two'}, copy)
+        assert.are_same(Blocks{Para('one'), CodeBlock 'two'}, blks)
+      end)
+    },
     group 'tostring' {
       test('works on an empty list', function ()
         assert.are_equal(tostring(Blocks{}), '[]')
diff --git a/test/test-inline.lua b/test/test-inline.lua
--- a/test/test-inline.lua
+++ b/test/test-inline.lua
@@ -325,6 +325,22 @@
         )
       end)
     },
+    group 'clone' {
+      test('function exists', function ()
+        assert.are_equal(type(Inlines({}).clone), 'function')
+      end),
+      test('clones the list', function ()
+        local inlns = Inlines{'Hello,', Space(), 'World!'}
+        assert.are_same(inlns, inlns:clone())
+      end),
+      test('deep-clones the list', function ()
+        local inlns = Inlines{Str 'Hello,', Space(), Str 'World!'}
+        local copy = inlns:clone()
+        copy[1].text = 'Bonjour,'
+        assert.are_same(Inlines{Str 'Bonjour,', Space(), Str 'World!'}, copy)
+        assert.are_same(Inlines{Str 'Hello,', Space(), Str 'World!'}, inlns)
+      end)
+    },
     group 'tostring' {
       test('works on an empty list', function ()
         assert.are_equal(
