Event Details

One event the user is interested in or invited to, with the time in the event's timezone, the venue, key facts, agenda and speakers, and RSVP and calendar actions.

Experience · Shares patterns with Summary Card, Map, Calendar

≈ 1,896 tokens per use (tool 1,320 · guidance 358 · typical payload 218)How token costs are estimated

Example: Event Details

Tell me about the design meetup on Thursday

People watching a speaker at a design meetup

Design Systems Night: tokens in practice

New York time · in 7 days
Acme Studio, 4th floor88 Front Street, Brooklyn, NY 11201Directions to Acme Studio, 4th floor (opens in a new tab)
Price
Free
Capacity
84 going · 120 spots
Accessibility
Step-free access · Accessible restroom

Two talks on design tokens, then lightning demos. Bring a laptop if you'd like to follow along.

Agenda

  1. 7:00 PM
    Tokens that survive a rebrandPriya Raman
  2. 7:40 PM
    From design variables to codeTomás Ferreira

When to use

  • The user asks about one specific event they're interested in or invited to: a conference, concert, meetup, webinar, wedding, match or class.
  • They want the when and where, the dress code, the agenda or who's speaking, or to RSVP, add it to their calendar or get tickets.

When not to use

  • The agent doesn't have the event from a tool result (an invite, a calendar, a ticketing or event page). Never invent times, venues, prices or attendee counts.
  • The user wants their ticket or entry code. Use Event Pass.
  • There are several events to choose from, or a whole day's schedule. Use a list or the Calendar.

How the agent should use it

  • Pass start and end with the venue's UTC offset and the event's IANA timeZone, exactly as the source gives them. Never convert times to the user's timezone.
  • Use a date-only start for all-day events ("2026-10-24"); end is then the last day.
  • Only include rsvp when the user can actually respond, with their current answer (none if they haven't).
  • Keep the description to facts the other fields don't cover, up to 600 characters, with **bold** for one or two key details.
  • Every action is a handoff. On rsvp, record the answer through the event's own system; get-tickets opens url; add-to-calendar and share happen on the device.
  • Lifecycle: set expiresAt on the call to the event's end (or the end of its last day), so a past event turns inert in the Renderer instead of offering RSVP and tickets. When the agent shows the same event again with updated details (a new time, a changed venue), supersede the old call. fetchedAt isn't needed.

Times and timezones

The date line shows in the event's own timezone: "Thu, Oct 15 · 6:30–9:00 PM". The line below names the zone ("New York time"), adds the start in the viewer's own time when it differs ("3:30 PM your time"), and how far away it is ("in 7 days", "tomorrow", "happening now", "ended").

EventDate line
Same dayThu, Oct 15 · 6:30–9:00 PM
No endThu, Oct 15 · 6:30 PM
Past midnightSat, Oct 24 · 4:00 PM – Sun 1:00 AM
Several daysThu, Oct 15, 9:00 AM – Sat, Oct 17, 5:00 PM
All daySat, Oct 24 · All day
Several days, all dayThu, Oct 15 – Sat, Oct 17

The year appears when it isn't the current one. The relative text and the viewer's time are computed after mount, so server and client render the same markup; pass now to measure from a fixed moment (tests, demos). Agenda times may be "18:30" (local time at the event) or ISO date-times. Formatting uses Intl only; the helpers are in event-details-utils.ts (resolveWhen, dateRangeText, relativeText, capacityText, directionsUrl, buildIcs, …).

Layout

  • Header: the title. kind picks the people heading ("Speakers", "Lineup") and isn't shown on its own.
  • When and where: the date line as the largest text, one quiet line under it, the venue with its address and a Directions link (an OpenStreetMap search), and for online or hybrid events the platform with its join link.
  • Key facts: price, capacity ("84 going · 120 spots"), dress code, age and accessibility, only those given.
  • Description, then the agenda as a compact timeline and the speakers (or lineup).
  • An optional image from the event's own data (http(s) or data:image only) sits on top.

Actions

ButtonWhenResult
Going / Maybe / Can't gorsvp is set and its deadline hasn't passed{ action: "rsvp", state }
Get tickets (Register when free)url is http(s){ action: "get-tickets" }, and opens url
Add to calendarAlways{ action: "add-to-calendar" }, and downloads an .ics
Share (icon button)Always{ action: "share" }, and opens the share sheet (or copies the details)

After an answer, the RSVP locks to it ("You're going") with a Change button that reopens the choice; a new answer sends another rsvp result. Answers close after rsvp.deadline. The calendar file is built in the browser: timed events in UTC, date-only events as all-day, with text escaped and long lines folded. Add to calendar, Get tickets and Share report once each.

Installation

npx shadcn@latest add https://your-site.com/r/event-details.json

Usage

app/api/chat/route.ts
import { tool } from "ai"
import { eventDetailsTool } from "@/components/genui/event-details.schema"

const tools = {
  // No execute: the user's first action is the tool result.
  [eventDetailsTool.name]: tool({
    description: eventDetailsTool.description,
    inputSchema: eventDetailsTool.inputSchema,
  }),
}

Render the tool call and hand each action to your own flow:

components/message.tsx
import { EventDetails } from "@/components/genui/event-details"

function ToolPart({ part, addToolResult }) {
  if (part.type !== "tool-show_event") return null

  return (
    <EventDetails
      {...part.input}
      status={part.state === "input-streaming" ? "streaming" : undefined}
      result={part.state === "output-available" ? part.output : undefined}
      onResult={(result) => {
        if (result.action === "rsvp") saveRsvp(result.state)
        if (part.state !== "output-available") {
          addToolResult({ tool: "show_event", toolCallId: part.toolCallId, output: result })
        } else {
          sendMessage({ text: `Event action: ${JSON.stringify(result)}` })
        }
      }}
    />
  )
}

The agent receives one of:

{ action: "rsvp", state: "going" } // or "maybe", "not-going"
{ action: "add-to-calendar" }
{ action: "get-tickets" }
{ action: "share" }

With LangGraph

Push it from a graph node with ui.push({ name: "show_event", props: { toolCallId, ...args } }, { message }), and render the thread's UI messages with the Renderer.

Restoring from history

When a conversation is reloaded, pass the stored result back as result, or an array when several actions were taken. The latest rsvp restores the locked answer (Change still works), and the other actions show as done. Restoring never calls onResult.

<EventDetails
  {...part.input}
  result={part.state === "output-available" ? part.output : undefined}
/>

Schema

PropTypeNotes
titlestringData-bound
kind"conference" | "concert" | "meetup" | "webinar" | "party" | "sports" | "class" | "other"Picks the people heading; not shown on its own
start / endstringISO 8601 with the venue's offset, or local time. A date only is all-day; end is then the last day. Data-bound
timeZonestringThe event's IANA timezone. Data-bound
allDayboolean?Treat the dates as all-day
venue{ name, address?, online?: { platform, url? } }?Directions with an address; join link http(s) only. Data-bound
descriptionstring?Up to 600 characters, plain text with **bold**
agenda{ time, title, speaker? }[]?Up to 12. time is "18:30" or ISO. Data-bound
people{ name, role? }[]?Speakers or lineup, up to 12. Data-bound
price"free" | { amount, currency }?ISO 4217 currency. Data-bound
capacity{ going, max? }?Data-bound
dressCode, ageLimitstring?
accessibilitystring[]?Up to 8, e.g. "Step-free access", "Live captions". Data-bound
rsvp{ state: "none" | "going" | "maybe" | "not-going", deadline? }?Adds the RSVP buttons. Data-bound
urlstring?Tickets or registration, http(s) only. Data-bound
image{ src, alt }?http(s) or data:image. Data-bound

Host props: status (streaming, ready, submitting, responded), locale, now, onResult, result and className.

Source

On this page