Card components provide a cross-platform way to create rich, interactive messages. They automatically convert to:
- Slack: Block Kit
- Teams: Adaptive Cards
- Google Chat: Card v2
Usage
Cards support both function calls and JSX syntax.
Function API
import { Card, Text, Actions, Button } from "chat";
await thread.post(
Card({
title: "Order #1234",
children: [
Text("Total: $50.00"),
Actions([
Button({ id: "approve", label: "Approve", style: "primary" }),
Button({ id: "reject", label: "Reject", style: "danger" })
])
]
})
);
JSX API
Requires jsxImportSource: "chat" in tsconfig.json.
/** @jsxImportSource chat */
import { Card, Text, Actions, Button } from "chat";
await thread.post(
<Card title="Order #1234">
<Text>Total: $50.00</Text>
<Actions>
<Button id="approve" style="primary">Approve</Button>
<Button id="reject" style="danger">Reject</Button>
</Actions>
</Card>
);
Card
Root container for card content.
Card title (displayed as header)
Card subtitle (displayed below title)
CardOptions Type
interface CardOptions {
title?: string;
subtitle?: string;
imageUrl?: string;
children?: CardChild[];
}
function Card(options: CardOptions): CardElement;
Text
Text content element.
Text content (supports markdown on some platforms)
style
'plain' | 'bold' | 'muted'
Text style
function Text(
content: string,
options?: { style?: "plain" | "bold" | "muted" }
): TextElement;
// Alias that avoids DOM Text constructor conflict
const CardText = Text;
Example:
Text("Hello, world!")
Text("Important", { style: "bold" })
Text("Note", { style: "muted" })
Image
Image element.
Alt text for accessibility
function Image(options: { url: string; alt?: string }): ImageElement;
Example:
Image({ url: "https://example.com/image.png", alt: "Description" })
Divider
Visual divider/separator.
function Divider(): DividerElement;
Example:
Card({
children: [
Text("Section 1"),
Divider(),
Text("Section 2")
]
})
Section
Container for grouping elements.
function Section(children: CardChild[]): SectionElement;
Example:
Section([
Text("Grouped content"),
Image({ url: "..." })
])
Actions
Container for buttons and selects.
function Actions(
children: (
| ButtonElement
| LinkButtonElement
| SelectElement
| RadioSelectElement
)[]
): ActionsElement;
Example:
Actions([
Button({ id: "ok", label: "OK" }),
Button({ id: "cancel", label: "Cancel" }),
LinkButton({ url: "https://example.com", label: "Learn More" })
])
Interactive button that triggers an action.
Unique action ID for callback routing
style
'primary' | 'danger' | 'default'
Visual style
Optional payload value sent with action callback
If true, button is displayed inactive and doesn’t respond to clicks
interface ButtonOptions {
id: string;
label: string;
style?: "primary" | "danger" | "default";
value?: string;
disabled?: boolean;
}
function Button(options: ButtonOptions): ButtonElement;
Example:
Button({ id: "submit", label: "Submit", style: "primary" })
Button({ id: "delete", label: "Delete", style: "danger", value: "item-123" })
Button({ id: "unavailable", label: "Unavailable", disabled: true })
Button that opens a URL when clicked.
style
'primary' | 'danger' | 'default'
Visual style
interface LinkButtonOptions {
url: string;
label: string;
style?: "primary" | "danger" | "default";
}
function LinkButton(options: LinkButtonOptions): LinkButtonElement;
Example:
LinkButton({ url: "https://example.com", label: "View Docs" })
LinkButton({ url: "https://example.com", label: "Learn More", style: "primary" })
Field
Key-value pair for displaying structured data.
function Field(options: { label: string; value: string }): FieldElement;
Example:
Field({ label: "Status", value: "Active" })
Fields
Container for multi-column field layout.
function Fields(children: FieldElement[]): FieldsElement;
Example:
Fields([
Field({ label: "Name", value: "John" }),
Field({ label: "Email", value: "[email protected]" }),
Field({ label: "Status", value: "Active" })
])
Table
Structured data table.
Data rows (each row is an array of cell strings)
align
('left' | 'center' | 'right')[]
Column alignment
interface TableOptions {
headers: string[];
rows: string[][];
align?: ("left" | "center" | "right")[];
}
function Table(options: TableOptions): TableElement;
Example:
Table({
headers: ["Name", "Age", "Role"],
rows: [
["Alice", "30", "Engineer"],
["Bob", "25", "Designer"]
],
align: ["left", "right", "left"]
})
CardLink
Inline hyperlink element.
function CardLink(options: { url: string; label: string }): LinkElement;
Example:
CardLink({ url: "https://example.com", label: "Visit Site" })
Complete Example
import { Card, Text, Image, Divider, Fields, Field, Actions, Button, LinkButton } from "chat";
await thread.post(
Card({
title: "Order Confirmation",
subtitle: "Order #1234",
imageUrl: "https://example.com/product.png",
children: [
Text("Your order has been received", { style: "bold" }),
Divider(),
Fields([
Field({ label: "Item", value: "Widget Pro" }),
Field({ label: "Quantity", value: "2" }),
Field({ label: "Total", value: "$50.00" })
]),
Divider(),
Actions([
Button({ id: "track", label: "Track Order", style: "primary" }),
Button({ id: "cancel", label: "Cancel", style: "danger" }),
LinkButton({ url: "https://example.com/help", label: "Help" })
])
]
})
);
Type Definitions
type CardChild =
| TextElement
| ImageElement
| DividerElement
| ActionsElement
| SectionElement
| FieldsElement
| LinkElement
| TableElement;
interface CardElement {
type: "card";
title?: string;
subtitle?: string;
imageUrl?: string;
children: CardChild[];
}
interface TextElement {
type: "text";
content: string;
style?: "plain" | "bold" | "muted";
}
interface ButtonElement {
type: "button";
id: string;
label: string;
style?: "primary" | "danger" | "default";
value?: string;
disabled?: boolean;
}