EventEditor
A side sheet with every field of an event: title, time, repeats, zone, place.
SourcePackage @weft-js/warp
Preview
tsx
import { state } from '@weft-js/core'import { Button, Card, EventEditor, Row, Stack, Text } from '@weft-js/warp'import type { CalEvent } from '@weft-js/warp-core'export function Change() { const open = state(false) const event = state(REVIEW) return ( <Card title={event.value.title} sweep={false}> <Stack gap="related"> <Text subtle>{when(event.value)}{event.value.location ? `, ${event.value.location}` : ''}</Text> <Row><Button emphasis="outline" tone="neutral" icon="settings" onClick={() => (open.value = true)}>Edit event</Button></Row> </Stack> <EventEditor open={open} event={event.value} calendars={TEAM_CALENDARS} timeZone={TEAM_ZONE} today={TODAY} locale="en-GB" onSave={e => (event.value = e)} /> </Card> )}const TODAY = '2026-11-03'const TEAM_ZONE = 'Europe/Stockholm'const TEAM_CALENDARS = ['Platform', 'Web', 'Data', 'Mobile', 'Releases', 'Time off'].map((name, i) => ({ id: i + 1, name }))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')!const when = (e: CalEvent) => `${e.start.slice(0, 10)}, ${e.start.slice(11)} to ${e.end.slice(11)}`Installation
npm install @weft-js/warpUsage
tsx
import { EventEditor } from '@weft-js/warp'A new event
A title is required, and the end must come after the start.
tsx
import { state } from '@weft-js/core'import { Button, EventEditor, Row, Stack, Text } from '@weft-js/warp'import type { CalEvent } from '@weft-js/warp-core'export function New() { const open = state(false) const added = state<CalEvent[]>([]) return ( <Stack gap="related"> {added.value.map(e => <Text key={e.id}>{e.title}: {when(e)}</Text>)} {!added.value.length && <Text subtle>Nothing added yet.</Text>} <Row><Button icon="plus" onClick={() => (open.value = true)}>New event</Button></Row> <EventEditor open={open} event={BLANK} isNew calendars={TEAM_CALENDARS} timeZone={TEAM_ZONE} today={TODAY} locale="en-GB" onSave={e => (added.value = [...added.value, { ...e, id: `new-${added.value.length}` }])} /> </Stack> )}const TODAY = '2026-11-03'const TEAM_ZONE = 'Europe/Stockholm'const TEAM_CALENDARS = ['Platform', 'Web', 'Data', 'Mobile', 'Releases', 'Time off'].map((name, i) => ({ id: i + 1, name }))const when = (e: CalEvent) => `${e.start.slice(0, 10)}, ${e.start.slice(11)} to ${e.end.slice(11)}`const BLANK: CalEvent = { id: 'new', title: '', start: `${TODAY}T14:00`, end: `${TODAY}T14:30`, cal: 1 }When to use
Use it for
- Creating or changing an event
- The way to do anything a drag can do
Accessibility
- Focus goes to the title on open and to the first problem on a failed save.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
open | State<boolean> | — | A state you own. |
event | CalEvent | null | — | The event to edit. Passing a new object rebuilds the fields. |
isNew | boolean | false | Titles it New event. |
calendars | CalendarSource[] | — | The calendars on offer. |
timeZone | string | — | The IANA zone the times are edited in, such as Europe/Berlin. |
locale | string | — | The language and region used to format values. |
today | string | — | Pins today's date, for server rendering and tests. The browser's clock otherwise. |
| Event | Type | Default | Description |
|---|---|---|---|
onSave | (e: CalEvent) => void | — | Gets the finished event. |
onCancel | (() => void) | — | Cancel was pressed. |