Skip to main content
PolyBot provides two approaches to constructing Telegram keyboards: a chainable fluent API for runtime-assembled markups, and a declarative source-generated approach where you annotate a partial method with [CallbackButton] attributes and the generator emits the implementation. Both produce standard Telegram.Bot markup types.
Fluent builders accumulate buttons linearly and then shape them into rows with Build() (one button per row) or Adjust(rowSizes) (explicit row widths, last size repeated for remaining buttons).

InlineKeyboardBuilder

Flat methods cover every button kind — callback, URL (string or Uri), copy-text, Web App, switch-inline-query variants, login, and pay — plus Add(...) for pre-built InlineKeyboardButtons. Row(...) composes an explicit row (via a nested InlineKeyboardRowBuilder or pre-built buttons); composed rows precede the flat buttons in Build().
Adjust(...) chunks only the flat buttons; composed rows are included by Build().

ReplyKeyboardBuilder

ReplyKeyboardBuilder mirrors the inline builder and always sets ResizeKeyboard = true on the produced markup. Beyond plain text buttons it covers the request-style buttons: contact, location, poll, users, chat, managed business bot, and Web App.

Adjust row-sizing rules

Adjust(params int[] rowSizes) chunks the flat button list into rows using the given widths in order. When the button list is longer than the specified sizes, the last size is repeated for all remaining buttons.

{parameter} placeholders in generated keyboards

Placeholders in CallbackData strings reference the declaring method’s parameters by name and are interpolated in the generated code at call time. Placeholders that don’t match any parameter name produce warning CUR017.
Partial properties have no parameters, so {parameter} placeholders only work on methods.

Requirements for generated keyboards

  • The containing type must be partial.
  • The method or property return type must be InlineKeyboardMarkup; any other type is a compile-time error (CUR018).
  • Non-partial members and generic methods produce warning CUR019 and are skipped.

Diagnostics reference

Severity: WarningA {name} placeholder in a [CallbackButton] attribute’s CallbackData does not match any parameter of the declaring method. The placeholder will be emitted as a literal string at runtime.
Severity: ErrorA [CallbackButton]-annotated method or property does not return InlineKeyboardMarkup. The generator skips the member.
Severity: WarningA [CallbackButton]-annotated member is not declared partial, or the method itself is generic. The generator cannot emit an implementation and skips the member.
Severity: ErrorA constant callback_data string passed to InlineKeyboardButton.WithCallbackData(...), InlineKeyboardBuilder.CallbackButton(...), or an InlineKeyboardButton object initializer is empty or longer than 64 bytes. The Bot API requires 1–64 bytes, so the button fails at runtime.
Severity: InfoA callback_data argument (same call sites as CUR050) is an interpolated string ($"item:{id}"). Consider a [CallbackButton]-generated keyboard with placeholders, or [Pattern] routing with CallbackPatternMatcher for typed, length-checked parsing.