diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/inline/PageCounter.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/inline/PageCounter.kt
new file mode 100644
index 00000000..4626bcc9
--- /dev/null
+++ b/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/inline/PageCounter.kt
@@ -0,0 +1,26 @@
+package eu.iamgio.quarkdown.ast.quarkdown.inline
+
+import eu.iamgio.quarkdown.ast.Node
+import eu.iamgio.quarkdown.visitor.node.NodeVisitor
+
+/**
+ * A counter for the current or total page number.
+ * In case the current document type does not support page counting (e.g. plain document),
+ * a placeholder is used at rendering time.
+ * @param target whether the counter should display the current or total page number
+ */
+data class PageCounter(val target: Target) : Node {
+    enum class Target {
+        /**
+         * The current page number.
+         */
+        CURRENT,
+
+        /**
+         * The total amount of pages.
+         */
+        TOTAL,
+    }
+
+    override fun <T> accept(visitor: NodeVisitor<T>): T = visitor.visit(this)
+}
diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/invisible/PageCounterInitializer.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/invisible/PageCounterInitializer.kt
deleted file mode 100644
index 0f1ffc2e..00000000
--- a/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/invisible/PageCounterInitializer.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package eu.iamgio.quarkdown.ast.quarkdown.invisible
-
-import eu.iamgio.quarkdown.ast.Node
-import eu.iamgio.quarkdown.document.page.PageMarginPosition
-import eu.iamgio.quarkdown.visitor.node.NodeVisitor
-
-/**
- * A non-visible node that triggers a property in paged documents that allows displaying a page counter on each page.
- * @param content action that returns the text of the counter.
- *                Arguments: index of the current page and total amount of pages.
- *                These are strings instead of numbers since the arguments can be placeholders.
- *                e.g. when using PagedJS for HTML rendering, CSS properties `counter(page)` and `counter(pages)` are used.
- * @param position position of the counter within the page
- */
-data class PageCounterInitializer(
-    val content: (String, String) -> List<Node>,
-    val position: PageMarginPosition,
-) : Node {
-    override fun <T> accept(visitor: NodeVisitor<T>) = visitor.visit(this)
-}
diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt
index 874ab178..a8aaba28 100644
--- a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt
+++ b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt
@@ -39,9 +39,9 @@ import eu.iamgio.quarkdown.ast.quarkdown.block.SlidesFragment
 import eu.iamgio.quarkdown.ast.quarkdown.block.Stacked
 import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView
 import eu.iamgio.quarkdown.ast.quarkdown.inline.MathSpan
+import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter
 import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransform
 import eu.iamgio.quarkdown.ast.quarkdown.inline.Whitespace
-import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer
 import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer
 import eu.iamgio.quarkdown.ast.quarkdown.invisible.SlidesConfigurationInitializer
 import eu.iamgio.quarkdown.context.Context
@@ -261,7 +261,7 @@ open class BaseHtmlNodeRenderer(context: Context) : TagNodeRenderer<HtmlTagBuild
 
     override fun visit(node: PageMarginContentInitializer): CharSequence = throw UnsupportedRenderException(node)
 
-    override fun visit(node: PageCounterInitializer): CharSequence = throw UnsupportedRenderException(node)
+    override fun visit(node: PageCounter): CharSequence = throw UnsupportedRenderException(node)
 
     override fun visit(node: SlidesConfigurationInitializer): CharSequence = throw UnsupportedRenderException(node)
 
diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt
index e78439bf..b614ed88 100644
--- a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt
+++ b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt
@@ -21,9 +21,9 @@ import eu.iamgio.quarkdown.ast.quarkdown.block.SlidesFragment
 import eu.iamgio.quarkdown.ast.quarkdown.block.Stacked
 import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView
 import eu.iamgio.quarkdown.ast.quarkdown.inline.MathSpan
+import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter
 import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransform
 import eu.iamgio.quarkdown.ast.quarkdown.inline.Whitespace
-import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer
 import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer
 import eu.iamgio.quarkdown.ast.quarkdown.invisible.SlidesConfigurationInitializer
 import eu.iamgio.quarkdown.context.Context
@@ -220,23 +220,19 @@ class QuarkdownHtmlNodeRenderer(context: Context) : BaseHtmlNodeRenderer(context
         // In slides and paged documents, these elements are copied to each page through the slides.js or paged.js script.
         div("page-margin-content page-margin-${node.position.asCSS}", node.children)
 
-    override fun visit(node: PageCounterInitializer) =
-        visit(
-            PageMarginContentInitializer(
-                children =
-                    node.content(
-                        // The current page number.
-                        tagBuilder("span")
-                            .`class`("current-page-number")
-                            .build(),
-                        // The total amount of pages.
-                        tagBuilder("span")
-                            .`class`("total-page-number")
-                            .build(),
-                    ),
-                position = node.position,
-            ),
-        )
+    override fun visit(node: PageCounter) =
+        // The current or total page number.
+        // The actual number is filled by a script at runtime
+        // (either slides.js or paged.js, depending on the document type).
+        buildTag("span") {
+            +"-" // The default placeholder in case it is not filled by a script (e.g. plain documents).
+            `class`(
+                when (node.target) {
+                    PageCounter.Target.CURRENT -> "current-page-number"
+                    PageCounter.Target.TOTAL -> "total-page-number"
+                },
+            )
+        }
 
     override fun visit(node: SlidesConfigurationInitializer): CharSequence =
         buildTag("script") {
diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt
index 002f4ba4..94dfb128 100644
--- a/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt
+++ b/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt
@@ -39,9 +39,9 @@ import eu.iamgio.quarkdown.ast.quarkdown.block.SlidesFragment
 import eu.iamgio.quarkdown.ast.quarkdown.block.Stacked
 import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView
 import eu.iamgio.quarkdown.ast.quarkdown.inline.MathSpan
+import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter
 import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransform
 import eu.iamgio.quarkdown.ast.quarkdown.inline.Whitespace
-import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer
 import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer
 import eu.iamgio.quarkdown.ast.quarkdown.invisible.SlidesConfigurationInitializer
 
@@ -140,13 +140,13 @@ interface NodeVisitor<T> {
 
     fun visit(node: TextTransform): T
 
+    fun visit(node: PageCounter): T
+
     fun visit(node: SlidesFragment): T
 
     // Quarkdown invisible nodes
 
     fun visit(node: PageMarginContentInitializer): T
 
-    fun visit(node: PageCounterInitializer): T
-
     fun visit(node: SlidesConfigurationInitializer): T
 }
diff --git a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt
index 5c2eb649..15027a69 100644
--- a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt
+++ b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt
@@ -3,9 +3,8 @@ package eu.iamgio.quarkdown.stdlib
 import eu.iamgio.quarkdown.ast.InlineMarkdownContent
 import eu.iamgio.quarkdown.ast.MarkdownContent
 import eu.iamgio.quarkdown.ast.base.block.Heading
-import eu.iamgio.quarkdown.ast.base.inline.Text
 import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView
-import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer
+import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter
 import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer
 import eu.iamgio.quarkdown.context.Context
 import eu.iamgio.quarkdown.context.MutableContext
@@ -25,7 +24,6 @@ import eu.iamgio.quarkdown.function.value.NodeValue
 import eu.iamgio.quarkdown.function.value.OutputValue
 import eu.iamgio.quarkdown.function.value.StringValue
 import eu.iamgio.quarkdown.function.value.VoidValue
-import eu.iamgio.quarkdown.function.value.data.Lambda
 import eu.iamgio.quarkdown.function.value.wrappedAsValue
 import eu.iamgio.quarkdown.pipeline.error.IOPipelineException
 
@@ -44,7 +42,8 @@ val Document: Module =
         ::pageFormat,
         ::pageMarginContent,
         ::footer,
-        ::pageCounter,
+        ::currentPage,
+        ::totalPages,
         ::autoPageBreak,
         ::disableAutoPageBreak,
         ::marker,
@@ -242,34 +241,22 @@ fun footer(content: MarkdownContent): NodeValue =
     )
 
 /**
- * Sets the global page counter for a paged document.
- * @param position position of the counter within the page
- * @param text action that returns the text of the counter.
- *             Accepts two arguments: index of the current page and total amount of pages.
- *             Markdown content is not supported.
- * @return a wrapped [PageCounterInitializer] node
+ * Displays the index (beginning from 1) of the page this element lies in.
+ * In case the current document type does not support page counting (e.g. plain document),
+ * a placeholder is used.
+ * @return a [PageCounter] node
  */
-@Name("pagecounter")
-fun pageCounter(
-    @Injected context: Context,
-    position: PageMarginPosition = PageMarginPosition.BOTTOM_CENTER,
-    text: Lambda =
-        Lambda(context) { (current, total), _ ->
-            "$current / $total".wrappedAsValue()
-        },
-): NodeValue =
-    PageCounterInitializer(
-        content = { current, total ->
-            val textValue =
-                text.invoke<String, StringValue>(
-                    StringValue(current),
-                    StringValue(total),
-                ).unwrappedValue
+@Name("currentpage")
+fun currentPage() = PageCounter(PageCounter.Target.CURRENT).wrappedAsValue()
 
-            listOf(Text(textValue))
-        },
-        position,
-    ).wrappedAsValue()
+/**
+ * Displays the total amount of pages in the document.
+ * In case the current document type does not support page counting (e.g. plain document),
+ * a placeholder is used.
+ * @return a [PageCounter] node
+ */
+@Name("totalpages")
+fun totalPages() = PageCounter(PageCounter.Target.TOTAL).wrappedAsValue()
 
 /**
  * Sets a new automatic page break threshold when a heading is found: