EventCard
Canonical calendar event surface for Google Calendar, Outlook, Cal.com, and any event 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/event-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 EventCard schema inline.
// Your app fetches (auth is yours)
const { data: event } = await calendar.events.get({
calendarId: "primary", eventId: "abc123",
})
// Map to the EventCard schema
const eventData = {
id: `google:${event.id}`,
provider: "google",
title: event.summary,
startAt: event.start.dateTime ?? event.start.date,
endAt: event.end.dateTime ?? event.end.date,
// ... map remaining fields
}// Your app fetches (auth is yours)
const event = await graphClient
.api("/me/events/AAMk...").get()
// Map to the EventCard schema
const eventData = {
id: `outlook:${event.id}`,
provider: "outlook",
title: event.subject,
startAt: event.start.dateTime,
endAt: event.end.dateTime,
// ... map remaining fields
}Usage as AI Tool
EventCard also works as a standard taw-ui tool output — let the AI populate the canonical schema directly.
import { tool } from "ai"
import { EventCardSchema } from "@/components/taw/event-card"
export const getEvent = tool({
description: "Look up a calendar event",
parameters: z.object({
query: z.string(),
}),
outputSchema: EventCardSchema,
execute: async ({ query }) => {
const event = await fetchNextEvent(query)
return {
id: \`google:\${event.id}\`,
provider: "google",
title: event.summary,
startAt: event.start.dateTime,
endAt: event.end.dateTime,
// ... map remaining fields
}
},
})import { EventCard } from "@/components/taw/event-card"
import type { ToolPart } from "@/components/taw/lib/types"
function ToolOutput({ part }: { part: ToolPart }) {
// Handles loading, error, and success states
return <EventCard part={part} />
}Providers
Switch between fixtures to see EventCard rendering data from different providers and states.
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. "google:abc123") |
| provider* | "google" | "outlook" | "calcom" | "other" | Source provider for icon and branding |
| title* | string | Event title / summary |
| startAt* | string | Start time (ISO 8601) or date (YYYY-MM-DD) |
| endAt* | string | End time (ISO 8601) or date (YYYY-MM-DD) |
| isAllDay | boolean | Whether this is an all-day event |
| description | string | Event description (truncated for display) |
| location | string | Physical location or room name |
| meetingUrl | string (URL) | Video meeting link (Zoom, Meet, Teams) |
| status | "confirmed" | "tentative" | "cancelled" | Event status — controls accent strip color |
| organizer | Organizer | Event organizer |
| attendees | Attendee[] | List of attendees with RSVP status |
| calendarName | string | Calendar name (e.g. "Work", "Personal") |
| url | string (URL) | Link back to the event in the provider |
| confidence | number (0-1) | AI confidence in this data |
| caveat | string | Uncertainty note |
| source | Source | Data provenance |
| Field | Type | Description |
|---|---|---|
| name* | string | Display name |
| string | Email address (display only) | |
| avatarUrl | string (URL) | Avatar image URL |
| Field | Type | Description |
|---|---|---|
| name* | string | Display name |
| string | Email address (display only) | |
| avatarUrl | string (URL) | Avatar image URL |
| responseStatus | "accepted" | "declined" | "tentative" | "needsAction" | RSVP response — shown as colored dot on avatar |
Data Mapping
Map your provider's API response to the EventCardSchema inline. No special adapters needed — just a plain object mapping.
// Map Google Calendar API v3 fields
const eventData = {
id: `google:${event.id}`,
provider: "google",
title: event.summary,
startAt: event.start.dateTime ?? event.start.date,
endAt: event.end.dateTime ?? event.end.date,
attendees: (event.attendees ?? []).map(a => ({
name: a.displayName ?? a.email,
email: a.email,
})),
}// Map Microsoft Graph API fields
const eventData = {
id: `outlook:${event.id}`,
provider: "outlook",
title: event.subject,
startAt: event.start.dateTime,
endAt: event.end.dateTime,
location: event.location?.displayName,
organizer: event.organizer
? { name: event.organizer.emailAddress.name }
: undefined,
}Features
Native icons for Google, Outlook, Cal.com — plus a generic calendar fallback
Left border colored by event status: green (confirmed), yellow (tentative), red (cancelled)
Locale-aware time display with duration badges and all-day event support
Stacked avatar display with RSVP response status indicators
Renders beautifully from minimal (5 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.