chat
Version:
Unified chat abstraction for Slack, Teams, Google Chat, and Discord
269 lines (203 loc) • 6.98 kB
text/mdx
---
title: Cards
description: Send rich interactive cards with buttons, fields, and images across all platforms.
type: guide
prerequisites:
- /docs/usage
related:
- /docs/actions
- /docs/modals
---
Cards let you send structured, interactive messages that render natively on each platform — Block Kit on Slack, Adaptive Cards on Teams, and Google Chat Cards.
## Setup
Configure your `tsconfig.json` to use the Chat SDK JSX runtime:
```json title="tsconfig.json"
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "chat"
}
}
```
Or use a per-file pragma:
```tsx title="lib/bot.tsx"
/** @jsxImportSource chat */
```
## Basic card
```tsx title="lib/bot.tsx" lineNumbers
import { Card, CardText, Button, Actions } from "chat";
await thread.post(
<Card title="Order #1234">
<CardText>Your order has been received!</CardText>
<Actions>
<Button id="approve" style="primary">Approve</Button>
<Button id="reject" style="danger">Reject</Button>
</Actions>
</Card>
);
```
## Components
### Card
The top-level container. Accepts `title` and optional `subtitle`.
```tsx title="lib/bot.tsx" lineNumbers
<Card title="My Card" subtitle="Optional subtitle">
{/* children */}
</Card>
```
### CardText
Renders formatted text. Supports a subset of markdown.
```tsx title="lib/bot.tsx" lineNumbers
<CardText>**Bold** and _italic_ text</CardText>
<CardText style="bold">Bold section header</CardText>
```
<Callout type="info">
Use `CardText` instead of `Text` when using JSX to avoid conflicts with React's built-in types.
</Callout>
### Section
Groups related content together.
```tsx title="lib/bot.tsx" lineNumbers
<Section>
<CardText>Section content here</CardText>
</Section>
```
### Fields
Renders key-value pairs in a compact layout.
```tsx title="lib/bot.tsx" lineNumbers
<Fields>
<Field label="Name" value="John Doe" />
<Field label="Role" value="Developer" />
<Field label="Team" value="Platform" />
</Fields>
```
### Button
An action button that triggers an `onAction` handler.
```tsx title="lib/bot.tsx" lineNumbers
<Button id="approve" style="primary">Approve</Button>
<Button id="reject" style="danger">Reject</Button>
<Button id="details">View Details</Button>
```
The `id` maps to your `onAction` handler. Optional `value` passes extra data:
```tsx title="lib/bot.tsx"
<Button id="report" value="bug">Report Bug</Button>
```
Set `actionType="modal"` to indicate the button opens a [modal](/docs/modals). The button still triggers your `onAction` handler, where you call `event.openModal()` — this prop tells adapters like Teams to wire up the button for dialog opening:
```tsx title="lib/bot.tsx"
<Button id="open-feedback" actionType="modal">Give Feedback</Button>
```
Optional `callbackUrl` causes the action data to be POSTed to a URL when clicked. See [Callback URLs](/docs/actions#callback-urls) for details.
```tsx title="lib/bot.tsx"
<Button callbackUrl={webhook.url} id="approve" style="primary">Approve</Button>
```
### CardLink
Inline hyperlink rendered as text. Unlike `LinkButton` (which must be inside `Actions`), `CardLink` can be placed directly in a card alongside other content.
```tsx title="lib/bot.tsx"
<CardLink url="https://example.com/order/1234" label="View order details" />
```
Or with children as the label:
```tsx title="lib/bot.tsx"
<CardLink url="https://example.com/docs">Read the docs</CardLink>
```
<Callout type="info">
`CardLink` renders as a platform-native link: `<url|label>` on Slack, `[label](url)` on Teams/Discord/GitHub/Linear, and `<a href>` on Google Chat.
</Callout>
### LinkButton
Opens an external URL. No `onAction` handler needed.
```tsx title="lib/bot.tsx"
<LinkButton url="https://example.com/order/1234">View Order</LinkButton>
```
### Actions
Container for buttons and interactive elements.
```tsx title="lib/bot.tsx" lineNumbers
<Actions>
<Button id="approve" style="primary">Approve</Button>
<Button id="reject" style="danger">Reject</Button>
<LinkButton url="https://example.com">View</LinkButton>
</Actions>
```
### Select
Inline dropdown menu.
```tsx title="lib/bot.tsx" lineNumbers
<Actions>
<Select id="priority" label="Priority" placeholder="Select priority">
<SelectOption label="High" value="high" description="Urgent tasks" />
<SelectOption label="Medium" value="medium" />
<SelectOption label="Low" value="low" />
</Select>
</Actions>
```
Selection triggers an `onAction` handler with the `id` as the `actionId` and the selected value.
### RadioSelect
Radio button group for mutually exclusive choices.
```tsx title="lib/bot.tsx" lineNumbers
<Actions>
<RadioSelect id="status" label="Status">
<SelectOption label="Open" value="open" />
<SelectOption label="In Progress" value="in_progress" />
<SelectOption label="Done" value="done" />
</RadioSelect>
</Actions>
```
### Table
Structured data display with column headers and rows. Renders as a native table on platforms that support it (Teams, GitHub, Linear) and as padded ASCII text elsewhere.
```tsx title="lib/bot.tsx" lineNumbers
<Table
headers={["Name", "Age", "Role"]}
rows={[
["Alice", "30", "Engineer"],
["Bob", "25", "Designer"],
]}
/>
```
Optional column alignment:
```tsx title="lib/bot.tsx"
<Table
headers={["Name", "Amount"]}
rows={[["Alice", "$100"], ["Bob", "$200"]]}
align={["left", "right"]}
/>
```
### Image
Embeds an image in the card.
```tsx title="lib/bot.tsx"
<Image url="https://example.com/screenshot.png" alt="Screenshot" />
```
### Divider
A visual separator between sections.
```tsx title="lib/bot.tsx" lineNumbers
<CardText>Above the line</CardText>
<Divider />
<CardText>Below the line</CardText>
```
## Full example
```tsx title="lib/bot.tsx" lineNumbers
import {
Card, CardText, CardLink, Button, LinkButton, Actions,
Section, Fields, Field, Divider, Image,
Select, SelectOption, RadioSelect,
} from "chat";
await thread.post(
<Card title="User Profile" subtitle="Account details">
<Image url="https://example.com/avatar.png" alt="User avatar" />
<Fields>
<Field label="Name" value="Jane Smith" />
<Field label="Role" value="Engineer" />
<Field label="Team" value="Platform" />
</Fields>
<CardLink url="https://example.com/profile/123">View full profile</CardLink>
<Divider />
<Section>
<CardText>Select an action below to manage this profile.</CardText>
</Section>
<Actions>
<Select id="role" label="Change Role" placeholder="Select role">
<SelectOption label="Engineer" value="engineer" />
<SelectOption label="Manager" value="manager" />
<SelectOption label="Admin" value="admin" />
</Select>
<Button id="edit" style="primary">Edit Profile</Button>
<Button id="deactivate" style="danger">Deactivate</Button>
<LinkButton url="https://example.com/profile/123">View Full Profile</LinkButton>
</Actions>
</Card>
);
```