chat
Version:
Unified chat abstraction for Slack, Teams, Google Chat, and Discord
283 lines (232 loc) • 5.91 kB
text/mdx
title: Cards
description: Rich card components for cross-platform interactive messages.
type: reference
Card components render natively on each platform — Block Kit on Slack, Adaptive Cards on Teams, Embeds on Discord, and Google Chat Cards.
```typescript
import { Card, Text, CardLink, Button, Actions, Section, Fields, Field, Divider, Image, LinkButton, Table } from "chat";
```
All components support both function-call and JSX syntax. Function-call syntax is recommended for better type inference.
## Card
Top-level container for a rich message.
```typescript
Card({
title: "Order #1234",
subtitle: "Pending approval",
children: [Text("Total: $50.00")],
})
```
<TypeTable
type={{
title: {
description: 'Card title.',
type: 'string',
},
subtitle: {
description: 'Card subtitle.',
type: 'string',
},
imageUrl: {
description: 'Header image URL.',
type: 'string',
},
children: {
description: 'Card content elements.',
type: 'CardChild[]',
},
}}
/>
## Text
Text content element. Use `CardText` instead of `Text` in JSX to avoid conflicts with React's built-in types.
```typescript
Text("Hello, world!")
Text("Important", { style: "bold" })
Text("Subtle note", { style: "muted" })
```
<TypeTable
type={{
content: {
description: 'Text content (first argument).',
type: 'string',
},
'options.style': {
description: 'Text style.',
type: '"plain" | "bold" | "muted"',
},
}}
/>
## Button
Interactive button that triggers an `onAction` handler.
```typescript
Button({ id: "approve", label: "Approve", style: "primary" })
Button({ id: "delete", label: "Delete", style: "danger", value: "item-123" })
```
<TypeTable
type={{
id: {
description: 'Unique action ID for callback routing.',
type: 'string',
},
label: {
description: 'Button label text.',
type: 'string',
},
style: {
description: 'Visual style.',
type: '"primary" | "danger" | "default"',
},
value: {
description: 'Optional payload sent with the action callback.',
type: 'string',
},
actionType: {
description: 'Hints to adapters like Teams that this button will open a modal via event.openModal().',
type: '"action" | "modal"',
default: '"action"',
},
callbackUrl: {
description: 'URL to POST action data to when this button is clicked.',
type: 'string',
},
}}
/>
## CardLink
Inline hyperlink rendered as text. Can be placed directly in a card alongside other content, unlike `LinkButton` which must live inside `Actions`.
```typescript
CardLink({ url: "https://example.com", label: "Visit Site" })
```
<TypeTable
type={{
url: {
description: 'URL to link to.',
type: 'string',
},
label: {
description: 'Link label text.',
type: 'string',
},
}}
/>
## LinkButton
Button that opens a URL. No `onAction` handler needed.
```typescript
LinkButton({ url: "https://example.com", label: "View Docs" })
```
<TypeTable
type={{
url: {
description: 'URL to open when clicked.',
type: 'string',
},
label: {
description: 'Button label text.',
type: 'string',
},
style: {
description: 'Visual style.',
type: '"primary" | "danger" | "default"',
},
}}
/>
## Actions
Container for buttons and interactive elements. Required wrapper around `Button`, `LinkButton`, `Select`, and `RadioSelect`.
```typescript
Actions([
Button({ id: "approve", label: "Approve", style: "primary" }),
Button({ id: "reject", label: "Reject", style: "danger" }),
LinkButton({ url: "https://example.com", label: "View" }),
])
```
## Section
Groups related content together.
```typescript
Section([
Text("Grouped content"),
Image({ url: "https://example.com/photo.png" }),
])
```
## Fields
Renders key-value pairs in a compact, multi-column layout.
```typescript
Fields([
Field({ label: "Name", value: "Jane Smith" }),
Field({ label: "Role", value: "Engineer" }),
])
```
## Field
A single key-value pair. Must be used inside `Fields`.
<TypeTable
type={{
label: {
description: 'Field label.',
type: 'string',
},
value: {
description: 'Field value.',
type: 'string',
},
}}
/>
## Image
Embeds an image in the card.
```typescript
Image({ url: "https://example.com/screenshot.png", alt: "Screenshot" })
```
<TypeTable
type={{
url: {
description: 'Image URL.',
type: 'string',
},
alt: {
description: 'Alt text for accessibility.',
type: 'string',
},
}}
/>
## Table
Structured data display with column headers and rows.
```typescript
Table({
headers: ["Name", "Age", "Role"],
rows: [
["Alice", "30", "Engineer"],
["Bob", "25", "Designer"],
],
})
```
<TypeTable
type={{
headers: {
description: 'Column header labels.',
type: 'string[]',
},
rows: {
description: 'Data rows (each row is an array of cell strings).',
type: 'string[][]',
},
align: {
description: 'Column alignment.',
type: '"left" | "center" | "right"[]',
},
}}
/>
On platforms with native table support (Teams, GitHub, Linear), tables render as formatted tables. On other platforms (Slack, Google Chat, Discord, Telegram), tables render as padded ASCII text.
## Divider
A visual separator between sections.
```typescript
Divider()
```
## CardChild types
The `children` array in `Card` and `Section` accepts these element types:
| Type | Created by |
|------|-----------|
| `TextElement` | `Text()` |
| `LinkElement` | `CardLink()` |
| `ImageElement` | `Image()` |
| `DividerElement` | `Divider()` |
| `ActionsElement` | `Actions()` |
| `SectionElement` | `Section()` |
| `FieldsElement` | `Fields()` |
| `TableElement` | `Table()` |