diff --git a/datafusion/functions/src/string/btrim.rs b/datafusion/functions/src/string/btrim.rs
index 298d64f04ae91..05a2f646e9698 100644
--- a/datafusion/functions/src/string/btrim.rs
+++ b/datafusion/functions/src/string/btrim.rs
@@ -21,12 +21,11 @@ use arrow::array::{ArrayRef, OffsetSizeTrait};
 use arrow::datatypes::DataType;
 use datafusion_common::{exec_err, Result};
 use datafusion_expr::function::Hint;
-use datafusion_expr::scalar_doc_sections::DOC_SECTION_STRING;
 use datafusion_expr::{
     ColumnarValue, Documentation, ScalarUDFImpl, Signature, TypeSignature, Volatility,
 };
+use datafusion_macros::user_doc;
 use std::any::Any;
-use std::sync::OnceLock;
 
 /// Returns the longest string with leading and trailing characters removed. If the characters are not specified, whitespace is removed.
 /// btrim('xyxtrimyyx', 'xyz') = 'trim'
@@ -35,6 +34,28 @@ fn btrim<T: OffsetSizeTrait>(args: &[ArrayRef]) -> Result<ArrayRef> {
     general_trim::<T>(args, TrimType::Both, use_string_view)
 }
 
+#[user_doc(
+    doc_section(label = "String Functions"),
+    description = "Trims the specified trim string from the start and end of a string. If no trim string is provided, all whitespace is removed from the start and end of the input string.",
+    syntax_example = "btrim(str[, trim_str])",
+    sql_example = r#"```sql
+> select btrim('__datafusion____', '_');
++-------------------------------------------+
+| btrim(Utf8("__datafusion____"),Utf8("_")) |
++-------------------------------------------+
+| datafusion                                |
++-------------------------------------------+
+```"#,
+    standard_argument(name = "str", prefix = "String"),
+    argument(
+        name = "trim_str",
+        description = r"String expression to operate on. Can be a constant, column, or function, and any combination of operators. _Default is whitespace characters._"
+    ),
+    alternative_syntax = "trim(BOTH trim_str FROM str)",
+    alternative_syntax = "trim(trim_str FROM str)",
+    related_udf(name = "ltrim"),
+    related_udf(name = "rtrim")
+)]
 #[derive(Debug)]
 pub struct BTrimFunc {
     signature: Signature,
@@ -106,36 +127,10 @@ impl ScalarUDFImpl for BTrimFunc {
     }
 
     fn documentation(&self) -> Option<&Documentation> {
-        Some(get_btrim_doc())
+        self.doc()
     }
 }
 
-static DOCUMENTATION: OnceLock<Documentation> = OnceLock::new();
-
-fn get_btrim_doc() -> &'static Documentation {
-    DOCUMENTATION.get_or_init(|| {
-        Documentation::builder(
-            DOC_SECTION_STRING,
-            "Trims the specified trim string from the start and end of a string. If no trim string is provided, all whitespace is removed from the start and end of the input string.",
-            "btrim(str[, trim_str])")
-            .with_sql_example(r#"```sql
-> select btrim('__datafusion____', '_');
-+-------------------------------------------+
-| btrim(Utf8("__datafusion____"),Utf8("_")) |
-+-------------------------------------------+
-| datafusion                                |
-+-------------------------------------------+
-```"#)
-            .with_standard_argument("str", Some("String"))
-            .with_argument("trim_str", "String expression to operate on. Can be a constant, column, or function, and any combination of operators. _Default is whitespace characters._")
-            .with_alternative_syntax("trim(BOTH trim_str FROM str)")
-            .with_alternative_syntax("trim(trim_str FROM str)")
-            .with_related_udf("ltrim")
-            .with_related_udf("rtrim")
-            .build()
-    })
-}
-
 #[cfg(test)]
 mod tests {
     use arrow::array::{Array, StringArray, StringViewArray};
diff --git a/datafusion/macros/src/user_doc.rs b/datafusion/macros/src/user_doc.rs
index 441b3db2a133b..e4b6a0f3b14ad 100644
--- a/datafusion/macros/src/user_doc.rs
+++ b/datafusion/macros/src/user_doc.rs
@@ -103,7 +103,7 @@ pub fn user_doc(args: TokenStream, input: TokenStream) -> TokenStream {
 
     let mut description: Option<LitStr> = None;
     let mut syntax_example: Option<LitStr> = None;
-    let mut alt_syntax_example: Option<LitStr> = None;
+    let mut alt_syntax_example: Vec<Option<LitStr>> = vec![];
     let mut sql_example: Option<LitStr> = None;
     let mut standard_args: Vec<(Option<LitStr>, Option<LitStr>)> = vec![];
     let mut udf_args: Vec<(Option<LitStr>, Option<LitStr>)> = vec![];
@@ -131,7 +131,7 @@ pub fn user_doc(args: TokenStream, input: TokenStream) -> TokenStream {
             syntax_example = Some(meta.value()?.parse()?);
             Ok(())
         } else if meta.path.is_ident("alternative_syntax") {
-            alt_syntax_example = Some(meta.value()?.parse()?);
+            alt_syntax_example.push(Some(meta.value()?.parse()?));
             Ok(())
         } else if meta.path.is_ident("sql_example") {
             sql_example = Some(meta.value()?.parse()?);
@@ -242,7 +242,7 @@ pub fn user_doc(args: TokenStream, input: TokenStream) -> TokenStream {
         })
         .collect::<Vec<_>>();
 
-    let alt_syntax_example = alt_syntax_example.map(|syn| {
+    let alt_syntax_example = alt_syntax_example.iter().map(|syn| {
         quote! {
             .with_alternative_syntax(#syn)
         }
@@ -258,7 +258,7 @@ pub fn user_doc(args: TokenStream, input: TokenStream) -> TokenStream {
                         datafusion_doc::Documentation::builder(datafusion_doc::DocSection { include: #doc_section_include, label: #doc_section_lbl, description: #doc_section_description },
                     #description.to_string(), #syntax_example.to_string())
                         #sql_example
-                        #alt_syntax_example
+                        #(#alt_syntax_example)*
                         #(#standard_args)*
                         #(#udf_args)*
                         #(#related_udfs)*
