Skip to content
Sign in
Apps SDKRSVP cardMenu

RSVP cardPro

An invite answered in the thread, drawn against your own calendar so a clash is seen before it is read, with a counter proposal from times you are free.

ProAn invite on a busy Thursday: the clash drawn on your day, and a free hour proposed back.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/rsvp-card

Usage

tsx
import { RsvpCard } from "@/components/ui/chatcn/pro/rsvp-card"

<RsvpCard
  title="Specimen review, Corvo Serif"
  start="2026-11-12T14:00:00Z"
  end="2026-11-12T15:00:00Z"
  organizer="Ilse Brandt"
  calendar={myThursday}
  timeZone="Europe/Lisbon"
  onReply={(reply) => sendReply(reply)}
  onPropose={(slot, note) => propose(slot, note)}
/>

Pass the viewer's other events that day as calendar. The card draws a few hours of that day as a ruler: your events on the top lane, the invite on the bottom one. An overlap lights an amber column through both lanes and hatches the part of the invite that clashes, and the line under the ruler names the clash in words. With nothing in the way it says so, in green.

Going, Maybe and Can't go are optimistic: the choice shows at once, and if onReply returns a promise that rejects, the reply rolls back and the card says how to fix it. Propose time opens free slots of the same length on the same day, nearest first, computed from calendar and workingHours unless you pass suggestions. The picked one is outlined on the ruler before it is sent.

Free to the free event-card, this adds the reply, the conflict check and the counter proposal. Render it inside the card your host draws for a widget answer. It fills the width it is given, so a comfortable max width (around 28 rem) comes from the card, and it follows the host theme through the kit tokens. Pass onExpand where the host can go full screen.

Examples

States

ProFree and going, a proposal sent, a failed reply, a long title with two clashes, cancelled, loading, an error and disabled.

Props

PropTypeNotes
title, start, end, locationThe event
organizerstringWho sent it
guests{ going?, maybe?, declined?, waiting? }Counts for the guest line
calendar{ title, start, end }[]Your other events that day
suggestions{ start, end }[]Times to propose. Defaults to computed free slots
workingHours[number, number]Hours a computed slot may use. Default 9 to 18
reply, defaultReply, onReply"going" | "maybe" | "declined"Optimistic
onPropose, proposal, onWithdrawCounter proposal, sent or not
status"ready" | "loading" | "error" | "cancelled"Default ready
timeZone, locale, hour12Formatting. Default en-GB
onRetry, disabled
labelsPartial<…Labels>Every string the widget writes, for translation

Labels

labels covers the three replies and their announcements, the propose panel, the clash and free lines, the ruler names, the organiser and guest lines, the cancelled copy and both error messages. clash(title, time), proposed(time, to), guests(counts) and range(from, to) are functions.

Keyboard

KeyAction
TabReply buttons, then Propose time
Enter or SpaceReply, or open the propose panel
Arrow keysMove between suggested times in the panel

Accessibility

  • Replies are toggle buttons with aria-pressed in a labelled group; the chosen reply is announced politely once it has been saved.
  • The ruler is a labelled figure, and every event on it keeps its name for screen readers even when it is too narrow to print it. The clash is also written out under the ruler, with an icon, not only drawn in amber.
  • Suggested times are a native radio group. Opening the panel moves focus to the first time.

Motion

The propose panel and the sent proposal enter with a 180 to 220 ms fade from 0.96. Reply buttons press to 0.97. Reduced motion keeps the fades only.