IssueCard
Canonical issue/ticket surface for GitHub, Linear, Jira, and any work-item provider. One component, any data source — your app authenticates, fetches, and maps to the canonical schema.
Installation
npx shadcn@latest add "https://taw-ui.com/r/issue-card.json"This copies the component source and schema into your project. You own the code — customize anything.
Usage with Data Mapping
The recommended pattern: your app fetches data from the provider and maps it to the IssueCard schema inline.
// Your app fetches (auth is yours)
const { data: issue } = await octokit.issues.get({
owner: "vercel", repo: "next.js", issue_number: 58234,
})
// Map to the IssueCard schema
const issueData = {
id: `github:${issue.number}`,
provider: "github",
title: issue.title,
number: issue.number,
status: { label: issue.state, color: issue.state === "open" ? "green" : "red" },
// ... map remaining fields
}// Your app fetches (auth is yours)
const issue = await linearClient.issue("issue-id")
// Map to the IssueCard schema
const issueData = {
id: `linear:${issue.identifier}`,
provider: "linear",
title: issue.title,
status: { label: issue.state.name, color: issue.state.color },
priority: issue.priority === 1 ? "urgent" : "medium",
// ... map remaining fields
}Usage as AI Tool
IssueCard also works as a standard taw-ui tool output — let the AI populate the canonical schema directly.
import { tool } from "ai"
import { IssueCardSchema } from "@/components/taw/issue-card"
export const getIssue = tool({
description: "Look up an issue",
parameters: z.object({
owner: z.string(),
repo: z.string(),
number: z.number(),
}),
outputSchema: IssueCardSchema,
execute: async ({ owner, repo, number }) => {
const issue = await fetchIssue(owner, repo, number)
return {
id: \`github:\${number}\`,
provider: "github",
title: issue.title,
status: { label: issue.state },
// ... map remaining fields
}
},
})import { IssueCard } from "@/components/taw/issue-card"
import type { ToolPart } from "@/components/taw/lib/types"
function ToolOutput({ part }: { part: ToolPart }) {
// Handles loading, error, and success states
return <IssueCard part={part} />
}Providers
Switch between fixtures to see IssueCard rendering data from different providers.
Props
| Field | Type | Description |
|---|---|---|
| part* | ToolPart | Tool call lifecycle state — handles loading, error, and success |
| animate | boolean | Enable entrance animations (default: true) |
| className | string | Additional CSS classes on the wrapper |
Schema
| Field | Type | Description |
|---|---|---|
| id* | string | Stable identifier (e.g. "github:owner/repo#42") |
| provider* | "github" | "linear" | "jira" | "other" | Source provider for icon and branding |
| title* | string | Issue title |
| number | number | Issue number (#123) |
| status* | Status | Normalized status with optional color |
| priority | "urgent" | "high" | "medium" | "low" | "none" | Priority level — controls accent strip color |
| assignee | Assignee | Assigned person with optional avatar |
| labels | Label[] | Tags/labels with optional colors |
| project | string | Project or repository name |
| url | string (URL) | Link back to the issue in the provider |
| createdAt | string | Creation timestamp (ISO 8601 or relative) |
| updatedAt | string | Last update timestamp |
| description | string | Issue body (truncated for display) |
| confidence | number (0-1) | AI confidence in this data |
| caveat | string | Uncertainty note |
| source | Source | Data provenance |
| Field | Type | Description |
|---|---|---|
| label* | string | Display text (e.g. "Open", "In Progress") |
| color | string | CSS color for the status badge |
| Field | Type | Description |
|---|---|---|
| name* | string | Display name or username |
| avatarUrl | string (URL) | Avatar image URL |
| Field | Type | Description |
|---|---|---|
| name* | string | Label text |
| color | string | CSS color for the label chip |
Data Mapping
Map your provider's API response to the IssueCardSchema inline. No special adapters needed — just a plain object mapping.
// Map GitHub REST API fields
const issueData = {
id: `github:${issue.number}`,
provider: "github",
title: issue.title,
number: issue.number,
status: { label: issue.state },
assignee: issue.assignee
? { name: issue.assignee.login }
: undefined,
}// Map Linear GraphQL fields
const issueData = {
id: `linear:${issue.identifier}`,
provider: "linear",
title: issue.title,
status: { label: issue.state.name,
color: issue.state.color },
priority: issue.priority === 1
? "urgent" : "medium",
}Features
Native SVG icons for GitHub, Linear, Jira — plus a generic fallback
Left border colored by priority level for instant visual signal
Color-coded status badge and label chips with provider colors
Assignee avatar, relative timestamps, project name, issue number
Renders beautifully from minimal (4 fields) to fully populated data
Map any provider's API response to the canonical schema — no adapters needed
Auth Boundary
taw-ui does not handle authentication. OAuth flows, access tokens, refresh tokens, API clients, and data fetching are the responsibility of your application. taw-ui provides schemas, components, and validation — nothing more.
See Domain Surfaces for the full architecture explanation.