Skip to main content

Cards and UI Components

The Chat SDK provides a unified API for creating rich cards that automatically convert to platform-specific formats:
  • Slack: Block Kit
  • Microsoft Teams: Adaptive Cards
  • Google Chat: Card v2
You can use either JSX syntax or function calls to build cards.

JSX Syntax

To use JSX, configure your tsconfig.json:
tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "chat"
  }
}
Then create cards with JSX:
/** @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>
);

Function API

Prefer function calls? Same result:
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" }),
      ]),
    ],
  })
);

Available Components

Card

The root container for all card content.
interface CardElement {
  type: "card";
  title?: string;
  subtitle?: string;
  imageUrl?: string;
  children: CardChild[];
}
Example:
<Card 
  title="Welcome" 
  subtitle="Getting started"
  imageUrl="https://example.com/banner.png"
>
  <Text>Hello world</Text>
</Card>

Text

Display text content with optional styling.
interface TextElement {
  type: "text";
  content: string;
  style?: "plain" | "bold" | "muted";
}
Example:
<Text style="bold">Important message</Text>
<Text style="muted">Secondary info</Text>
Use CardText instead of Text if you need to avoid conflicts with the global DOM Text constructor.

Image

Embed images in your cards.
interface ImageElement {
  type: "image";
  url: string;
  alt?: string;
}
Example:
<Image 
  url="https://example.com/chart.png" 
  alt="Sales chart"
/>

Divider

A visual separator between sections.
<Divider />

Section

Group related content together.
<Section>
  <Text>Grouped content</Text>
  <Image url="..." />
</Section>

Fields

Display key-value pairs in a multi-column layout.
interface FieldElement {
  type: "field";
  label: string;
  value: string;
}
Example:
<Fields>
  <Field label="Status" value="Active" />
  <Field label="Priority" value="High" />
  <Field label="Assignee" value="Alice" />
</Fields>

Table

Display structured data in a table format.
interface TableElement {
  type: "table";
  headers: string[];
  rows: string[][];
  align?: ("left" | "center" | "right")[];
}
Example:
<Table
  headers={["Name", "Age", "Role"]}
  rows={[
    ["Alice", "30", "Engineer"],
    ["Bob", "25", "Designer"],
  ]}
  align={["left", "center", "right"]}
/>
Inline hyperlink element.
<CardLink url="https://example.com" label="Visit Site" />

Complete Example

Here’s a comprehensive card showcasing multiple components:
/** @jsxImportSource chat */
import { Card, Text, Image, Divider, Fields, Field, Table, Actions, Button, LinkButton } from "chat";

await thread.post(
  <Card 
    title="Project Status Report"
    subtitle="Q1 2024"
    imageUrl="https://example.com/logo.png"
  >
    <Text style="bold">Executive Summary</Text>
    <Text>All milestones on track for Q1 delivery.</Text>
    
    <Divider />
    
    <Fields>
      <Field label="Status" value="On Track" />
      <Field label="Budget" value="$250K" />
      <Field label="Team Size" value="12" />
    </Fields>
    
    <Divider />
    
    <Text style="bold">Milestone Progress</Text>
    <Table
      headers={["Milestone", "Progress", "Due Date"]}
      rows={[
        ["Design", "100%", "Jan 15"],
        ["Development", "75%", "Feb 28"],
        ["Testing", "25%", "Mar 15"],
      ]}
    />
    
    <Actions>
      <Button id="approve" style="primary">Approve</Button>
      <Button id="comment" style="default">Add Comment</Button>
      <LinkButton url="https://project.example.com" label="View Details" />
    </Actions>
  </Card>
);

Fallback Text

Cards automatically generate plain text fallbacks for platforms or clients that can’t render rich cards:
import { cardToFallbackText } from "chat";

const fallback = cardToFallbackText(myCard);
// Returns markdown-formatted plain text

React Integration

If you’re using React components, convert them to card elements:
import { fromReactElement } from "chat";
import React from "react";

const reactElement = (
  <Card title="Hello">
    <Text>World</Text>
  </Card>
);

const cardElement = fromReactElement(reactElement);
await thread.post(cardElement);

Next Steps

Actions

Add interactive buttons and handle clicks

Modals

Create forms and dialog workflows