Cards
Build rich, structured messages with a platform-agnostic Ruby DSL that renders natively on each platform.
Cards are rich, structured messages that render natively on each platform: Block Kit on Slack, Adaptive Cards on Teams, and Card v2 on Google Chat. ChatSDK provides a Ruby DSL for building cards that is platform-agnostic.
Building a Card
Use ChatSDK.card with a block:
card = ChatSDK.card(title: "Incident Report", subtitle: "INC-42") do
text "Database connection pool exhausted"
fields do
field "Severity", "SEV1"
field "Status", "Investigating"
field "Duration", "12 minutes"
end
divider
section "Affected Services" do
text "- API Gateway"
text "- User Service"
end
image url: "https://example.com/chart.png", alt: "Error rate graph"
actions do
button "Acknowledge", id: "ack_btn", style: :primary, value: "inc-42"
button "Escalate", id: "escalate_btn", style: :danger
link_button "View Dashboard", url: "https://example.com/dashboard"
end
endPost the card like any other message:
thread.post(card)Node Types
text
Renders a block of text content.
ChatSDK.card do
text "Hello, **world**!"
endfields
Renders key-value pairs in a compact layout (two columns on most platforms).
ChatSDK.card do
fields do
field "Status", "Active"
field "Region", "us-east-1"
field "Uptime", "99.9%"
end
enddivider
A horizontal rule separating sections.
ChatSDK.card do
text "Above the line"
divider
text "Below the line"
endimage
Displays an image.
ChatSDK.card do
image url: "https://example.com/logo.png", alt: "Company logo"
endsection
Groups child elements under an optional title.
ChatSDK.card do
section "Details" do
text "Some details here"
fields do
field "Key", "Value"
end
end
endactions
Contains interactive elements: buttons, link buttons, and select menus.
ChatSDK.card do
actions do
button "Click me", id: "btn_1"
button "Danger", id: "btn_2", style: :danger, value: "dangerous"
link_button "Open URL", url: "https://example.com"
select id: "priority_select", placeholder: "Choose priority" do
option "Low", value: "low"
option "Medium", value: "medium", description: "Default priority"
option "High", value: "high"
end
end
endButton Styles
Buttons accept an optional style: parameter:
:primary-- Emphasized button (green on Slack, accent color on Teams):danger-- Destructive action (red on most platforms)nil-- Default/neutral style
Button Values
Attach a value: to buttons to distinguish which option was selected when handling the action:
actions do
button "Approve", id: "review_btn", value: "approve"
button "Reject", id: "review_btn", value: "reject"
endIn your action handler:
bot.on_action("review_btn") do |event|
case event.value
when "approve" then event.thread.post("Approved!")
when "reject" then event.thread.post("Rejected.")
end
endSelect Menus
Select menus let users choose from a list of options.
ChatSDK.card do
actions do
select id: "env_select", placeholder: "Choose environment" do
option "Production", value: "prod"
option "Staging", value: "staging"
option "Development", value: "dev", description: "Local dev cluster"
end
end
endHandle selections with on_action:
bot.on_action("env_select") do |event|
event.thread.post("You selected: #{event.value}")
endCards with Text Fallback
When you pass a card to thread.post, ChatSDK automatically generates a plain-text fallback from the card's content. This fallback is used for push notifications and platforms that cannot render rich cards.
If you need to customize the fallback, use PostableMessage directly:
msg = ChatSDK::PostableMessage.new(
text: "Custom notification text",
card: ChatSDK.card(title: "Rich Card") { text "Details" }
)
thread.post(msg)How Cards Render
The same card DSL renders differently depending on the adapter:
- Slack -- Rendered as Block Kit JSON via
BlockKitRenderer - Teams -- Rendered as Adaptive Card JSON via
AdaptiveCardRenderer - Google Chat -- Rendered as Card v2 JSON via
CardV2Renderer
You never need to interact with these renderers directly. The adapter handles it when you call thread.post(card).