EventPopover
A small card with an event's details, hung from wherever it was opened.
SourcePackage @weft-js/warp
Preview
tsx
import { state } from '@weft-js/core'import { Button, EventPopover, Stack, Text } from '@weft-js/warp'import type { CalEvent } from '@weft-js/warp-core'export function Details() { const open = state(false) const said = state('Open the event, then join, edit or delete it.') let opener: HTMLElement | undefined return ( <Stack gap="related" align="center"> <Button ref={(n: HTMLElement) => (opener = n)} emphasis="outline" tone="neutral" onClick={() => (open.value = !open.value)}>{REVIEW.title}</Button> <Text role="caption" subtle>{said.value}</Text> <EventPopover event={REVIEW} open={open} anchor={() => opener} side="bottom" align="center" zoneLabel="Stockholm (CET)" locale="en-GB" hourCycle="h23" onJoin={() => (said.value = 'Joining the call')} onEdit={() => (said.value = 'Editing')} onDelete={() => (said.value = 'Deleted')} /> </Stack> )}const TEAM_EVENTS: CalEvent[] = [ { id: 'e1', title: 'Platform standup', start: '2026-11-02T09:00', end: '2026-11-02T09:15', cal: 1, recurrence: 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR', location: 'Room Atlas', attendees: ['Mara Lindqvist', 'Jun Tanaka'] }, { id: 'e2', title: 'Platform standup', start: '2026-11-03T09:00', end: '2026-11-03T09:15', cal: 1, recurrence: 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR', location: 'Room Atlas', attendees: ['Mara Lindqvist', 'Jun Tanaka'] }, { id: 'e3', title: 'Checkout review', start: '2026-11-03T10:00', end: '2026-11-03T11:00', cal: 2, video: true, attendees: ['Priya Raman', 'Tomás Oliveira', 'Mara Lindqvist'] }, { id: 'e4', title: 'Incident review: mobile-bff', start: '2026-11-03T13:00', end: '2026-11-03T13:45', cal: 4, video: true, location: 'Room Birch', attendees: ['Sam Okafor', 'Inés Vidal', 'Jun Tanaka'] }, { id: 'e5', title: 'Ranking v2 handover', start: '2026-11-03T15:00', end: '2026-11-03T16:00', cal: 3, location: 'Room Cedar', attendees: ['Lena Fischer', 'Noor Haddad'] }, { id: 'e6', title: 'Priya out of office', start: '2026-11-03', end: '2026-11-03', allDay: true, cal: 6 }, { id: 'e7', title: 'Release 2026.11', start: '2026-11-04T11:00', end: '2026-11-04T12:00', cal: 5, attendees: ['Mara Lindqvist', 'Jun Tanaka', 'Tomás Oliveira'] }, { id: 'e8', title: 'Design crit', start: '2026-11-04T14:00', end: '2026-11-04T15:00', cal: 2, tentative: true, video: true }, { id: 'e9', title: 'Cost review', start: '2026-11-05T10:00', end: '2026-11-05T11:00', cal: 1, recurrence: 'FREQ=MONTHLY', attendees: ['Mara Lindqvist', 'Lena Fischer'] }, { id: 'e10', title: 'On-call handover', start: '2026-11-06T16:00', end: '2026-11-06T16:30', cal: 1, recurrence: 'FREQ=WEEKLY', video: true },]const REVIEW = TEAM_EVENTS.find(e => e.id === 'e4')!Installation
npm install @weft-js/warpUsage
tsx
import { EventPopover } from '@weft-js/warp'Accessibility
- Escape
- Closes and returns to the event
- It is a non-modal dialog, so the rest of the page stays usable.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
event | CalEvent | null | — | The event to show. |
open | State<boolean> | — | A state you own. |
anchor | () => HTMLElement | — | Returns the element it hangs from. Focus goes back there. |
zoneLabel | string | — | Such as "Stockholm (CET)". |
locale | string | — | The language and region used to format values. |
hourCycle | string | — | h12 for AM and PM, h23 for a 24-hour clock. The locale's otherwise. |
side | Side | — | Which edge it sits on. |
align | Align | — | How it lines up with what opened it. |
| Event | Type | Default | Description |
|---|---|---|---|
onEdit | ((e: CalEvent) => void) | — | Adds Edit. |
onDelete | ((e: CalEvent) => void) | — | Adds Delete. |
onJoin | ((e: CalEvent) => void) | — | Join was pressed. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="popover"] [data-part="content"]
contenttitleactions
RelatedEvent editorPopover