Skip to content
weftGitHub

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/warp

Usage

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

PropTypeDefaultDescription
eventCalEvent | null—The event to show.
openState<boolean>—A state you own.
anchor() => HTMLElement—Returns the element it hangs from. Focus goes back there.
zoneLabelstring—Such as "Stockholm (CET)".
localestring—The language and region used to format values.
hourCyclestring—h12 for AM and PM, h23 for a 24-hour clock. The locale's otherwise.
sideSide—Which edge it sits on.
alignAlign—How it lines up with what opened it.
EventTypeDefaultDescription
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