diff --git a/src/resources/extensions/quarto/kbd/kbd.lua b/src/resources/extensions/quarto/kbd/kbd.lua
index 47fd4737d2c..f65e5a38b5b 100644
--- a/src/resources/extensions/quarto/kbd/kbd.lua
+++ b/src/resources/extensions/quarto/kbd/kbd.lua
@@ -32,10 +32,30 @@ return {
end
return pandoc.RawInline('html', '' .. default_arg_str .. '' .. default_arg_str .. '')
- elseif quarto.doc.isFormat("asciidoc") and args and #args == 1 then
- -- get the 'first' kbd shortcut as we can only produce on shortcut in asciidoc
- local shortcutText = pandoc.utils.stringify(args[1]):gsub('-', '+')
- return pandoc.RawInline("asciidoc", "kbd:[" .. shortcutText .. "]")
+ elseif quarto.doc.isFormat("asciidoc") then
+ if args and #args == 1 then
+ -- https://docs.asciidoctor.org/asciidoc/latest/macros/keyboard-macro/
+
+ -- get the 'first' kbd shortcut as we can only produce one shortcut in asciidoc
+ local shortcutText = pandoc.utils.stringify(args[1]):gsub('-', '+')
+
+ -- from the docs:
+ -- If the last key is a backslash (\), it must be followed by a space.
+ -- Without this space, the processor will not recognize the macro.
+ -- If one of the keys is a closing square bracket (]), it must be preceded by a backslash.
+ -- Without the backslash escape, the macro will end prematurely.
+
+ if shortcutText:sub(-1) == "\\" then
+ shortcutText = shortcutText .. " "
+ end
+ if shortcutText:find("]") then
+ shortcutText = shortcutText:gsub("]", "\\]")
+ end
+
+ return pandoc.RawInline("asciidoc", "kbd:[" .. shortcutText .. "]")
+ else
+ return quarto.shortcode.error_output("kbd", "kbd only supports one positional argument", "inline")
+ end
else
-- example shortcodes
-- {{< kbd Shift-Ctrl-P >}}
diff --git a/tests/docs/smoke-all/2025/04/09/kbd-adoc-bad-input.qmd b/tests/docs/smoke-all/2025/04/09/kbd-adoc-bad-input.qmd
new file mode 100644
index 00000000000..60636a30ac4
--- /dev/null
+++ b/tests/docs/smoke-all/2025/04/09/kbd-adoc-bad-input.qmd
@@ -0,0 +1,5 @@
+---
+format: asciidoc
+---
+
+{{< kbd key="\\" >}}
\ No newline at end of file