diff --git a/src/commonMain/kotlin/fragment.kt b/src/commonMain/kotlin/fragment.kt
new file mode 100644
index 00000000..8dc6f190
--- /dev/null
+++ b/src/commonMain/kotlin/fragment.kt
@@ -0,0 +1,7 @@
+package kotlinx.html
+
+@HtmlTagMarker
+inline fun <T, C : TagConsumer<T>> C.fragment(crossinline block: DIV.() -> Unit): T {
+    DIV(emptyMap, this).block()
+    return this.finalize()
+}
diff --git a/src/jvmTest/kotlin/fragment.kt b/src/jvmTest/kotlin/fragment.kt
new file mode 100644
index 00000000..b1edce0a
--- /dev/null
+++ b/src/jvmTest/kotlin/fragment.kt
@@ -0,0 +1,36 @@
+package kotlinx.html.tests
+
+import kotlinx.html.*
+import kotlinx.html.stream.*
+import org.junit.Test
+import kotlin.test.*
+
+class FinalizeCounter<T>(val delegate: TagConsumer<T>) : TagConsumer<T> by delegate {
+    var count = 0
+
+    override fun finalize(): T {
+        count++
+        return delegate.finalize()
+    }
+}
+
+class FragmentTest {
+    @Test
+    fun testFragment() {
+        val finalizeCounter = FinalizeCounter(createHTML(false))
+        val html = finalizeCounter.fragment {
+            p {
+                +"One"
+            }
+            p {
+                +"Two"
+            }
+            p {
+                +"Three"
+            }
+        }
+
+        assertEquals("<p>One</p><p>Two</p><p>Three</p>", html)
+        assertEquals(1, finalizeCounter.count)
+    }
+}