diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,22 @@
 
 `pandoc-lua-marshal` uses [PVP Versioning][].
 
+## 0.2.7
+
+Released 2024-05-06.
+
+-   Let the behavior of `content` attributes on BulletList and
+    OrderedList elements match that of the constructor by treating
+    a list of Block elements as a list of single-block items. The
+    following assertion now holds true:
+
+    ``` lua
+    local content = {pandoc.Plain "one", pandoc.Plain "two"}
+    local bl = pandoc.BulletList{}
+    bl.content = content
+    assert(bl == pandoc.BulletList(content))
+    ```
+
 ## 0.2.6
 
 Released 2024-03-29.
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.6
+version:             0.2.7
 synopsis:            Use pandoc types in Lua
 description:         This package provides functions to marshal and unmarshal
                      pandoc document types to and from Lua.
@@ -109,7 +109,7 @@
   hs-source-dirs:      test
   main-is:             test-pandoc-lua-marshal.hs
   build-depends:       pandoc-lua-marshal
-                     , QuickCheck           >= 2.4     && < 2.15
+                     , QuickCheck           >= 2.4     && < 2.16
                      , tasty                >= 0.11
                      , tasty-hunit          >= 0.9
                      , tasty-lua            >= 1.0
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
@@ -307,7 +307,7 @@
       c -> throwM . luaException @e $
            "expected definition items, got " <> contentTypeDescription c
     listItemContent = \case
-      ContentBlocks blks    -> [blks]
+      ContentBlocks blks    -> map (:[]) blks
       ContentLines lns      -> map ((:[]) . Plain) lns
       ContentListItems itms -> itms
       c -> throwM . luaException @e $
diff --git a/src/Text/Pandoc/Lua/Marshal/Content.hs b/src/Text/Pandoc/Lua/Marshal/Content.hs
--- a/src/Text/Pandoc/Lua/Marshal/Content.hs
+++ b/src/Text/Pandoc/Lua/Marshal/Content.hs
@@ -39,7 +39,7 @@
   | ContentDefItems [([Inline], [[Block]])]
   | ContentListItems [[Block]]
 
--- | Gets the text property of an Inline, if present.
+-- | Returns a human-readable type description; used for error messages.
 contentTypeDescription :: Content -> String
 contentTypeDescription = \case
   ContentBlocks {}    -> "list of Block items"
diff --git a/test/test-block.lua b/test/test-block.lua
--- a/test/test-block.lua
+++ b/test/test-block.lua
@@ -9,7 +9,7 @@
     group 'BlockQuote' {
       test('access content via property `content`', function ()
         local elem = BlockQuote{'word'}
-        assert.are_same(elem.content, {Plain 'word'})
+        assert.are_equal(elem.content, Blocks{Plain 'word'})
         assert.are_equal(type(elem.content), 'table')
 
         elem.content = {
@@ -29,16 +29,47 @@
       test('access items via property `content`', function ()
         local para = Para 'one'
         local blist = BulletList{{para}}
-        assert.are_same({{para}}, blist.content)
+        assert.are_equal(List{Blocks{para}}, blist.content)
       end),
+      test('property `content` is a list of Block lists', function ()
+        local items = List{Blocks{Plain 'item 1'}, Blocks{Plain 'item 2'}}
+        local blist = BulletList{}
+        blist.content = items
+        assert.are_equal(items, blist:clone().content)
+      end),
       test('property `content` uses fuzzy marshalling', function ()
-        local old = Plain 'old'
         local new = Plain 'new'
-        local blist = BulletList{{old}}
+        local blist = BulletList{{Plain 'old'}}
         blist.content = {{new}}
-        assert.are_same({{new}}, blist:clone().content)
+        assert.are_equal(List{Blocks{new}}, blist:clone().content)
         blist.content = new
-        assert.are_same({{new}}, blist:clone().content)
+        assert.are_equal(List{Blocks{new}}, blist:clone().content)
+      end),
+      test('property `content` prioritizes lists', function ()
+        local blist = BulletList{}
+        local one, two = Para 'one', Plain 'two'
+        blist.content = {one, two}
+        assert.are_equal(
+          List{Blocks{one}, Blocks{two}},
+          blist:clone().content
+        )
+      end),
+      test('behavior is consistent with constructor', function ()
+        local content = {Para 'one', CodeBlock 'print "Hello"'}
+        local bl1 = BulletList(content)
+        local bl2 = BulletList{}
+        bl2.content = content
+        assert.are_equal(bl1, bl2)
+      end),
+      test('mixing types works', function ()
+             local one = Plain 'one'
+        local two = 'two'
+        local blist = BulletList{}
+        blist.content = {one, two}
+        assert.are_same(
+          List{Blocks{one}, Blocks{Plain(two)}},
+          blist:clone().content
+        )
       end),
     },
     group 'CodeBlock' {
