Calendar View
The calendar view renders an interactive calendar powered by FullCalendar. Events are embedded in the spec by the server — the UI displays them and optionally supports drag-drop rescheduling and date-click creation.
Spec
CalendarView.events(events)
.defaultView('month')
.title('Team Calendar')
.build()How it works
The SPA navigates to #/{resource}/calendar and fetches a CalendarSpec from GET /api/ui/{resource}/calendar. The spec includes all events pre-populated — no secondary fetches for initial render.
FullCalendar is initialized from the spec's events array and options. Subsequent interactions (clicking an event, dragging to reschedule) call your CRUD endpoints directly.
Basic setup (JS)
import { CalendarView } from '@retrofit-ui/builder-zod';
// URL prefix below is arbitrary — pick anything and match `apiBase` to it.
app.get('/schedule/events/calendar', async (_req, res) => {
const events = await db.query(
`SELECT id::text, title, start_at AS start, end_at AS end, color
FROM events WHERE start_at >= NOW() - INTERVAL '30 days'`,
);
res.json(
CalendarView.events(events)
.defaultView('month')
.title('Team Calendar')
.build(),
);
});Event fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Unique identifier (must be a string) |
title | string | ✓ | Event label shown on the calendar |
start | string | ✓ | ISO 8601 datetime or date string |
end | string | — | ISO 8601 datetime or date string |
color | string | — | CSS colour for this event's chip |
allDay | boolean | — | Renders as an all-day event when true |
CalendarView.events([
{
id: '1',
title: 'Team standup',
start: '2026-06-15T09:00:00',
end: '2026-06-15T09:30:00',
color: '#3b82f6',
},
{
id: '2',
title: 'Company holiday',
start: '2026-06-20',
allDay: true,
color: '#22c55e',
},
]).build();View modes
CalendarView.events(events)
.defaultView('week') // 'month' | 'week' | 'day' | 'list'
.build();| Mode | FullCalendar view | Shows |
|---|---|---|
'month' (default) | dayGridMonth | Month grid |
'week' | timeGridWeek | 7-day time grid |
'day' | timeGridDay | Single-day time grid |
'list' | listWeek | Plain list of upcoming events |
Users can switch between all four views using the toolbar buttons.
CRUD endpoints
Configure endpoints to enable event interactions:
CalendarView.events(events)
.find({ method: 'GET', url: '/events/{id}' }) // event click → navigate to detail form
.create({ method: 'POST', url: '/events' }) // date click → navigate to new form
.update({ method: 'PUT', url: '/events/{id}' }) // drag-drop / resize → API call
.delete({ method: 'DELETE', url: '/events/{id}' }) // for use via the renderer
.editable()
.build();| Endpoint | Trigger | Behaviour |
|---|---|---|
find | Click on an event | Navigates to #/{resource}/{id} |
create | Click on an empty date | Navigates to #/{resource}/new?start={date} |
update | Drag-drop or resize an event | Calls the endpoint with { start, end } in the body; reverts if the request fails |
delete | (no UI trigger) | Used by the renderer or custom integrations |
editable() must be set alongside update to enable drag-drop and resize. Without it, events are read-only even if update is defined.
Editable calendar
- Drag to reschedule — drops the event on a new date/time and PATCHes the server
- Resize — drag the event's edge to change its end time
Spec
CalendarView.events(events)
.update({ method: 'PATCH', url: '/events/{id}' })
.editable()
.build();Using the standalone renderer
<script src="retrofit-ui.iife.js"></script>
<!-- declarative island — auto-mounted by init() -->
<div data-retrofit-src="/specs/calendar.json"></div>
<!-- or mount explicitly in JS -->
<div id="cal" style="height: 600px;"></div>
<script>
const ui = RetrofitUI.init({ rootElement: document.body, apiBase: '/api' });
ui.mount(
{
kind: 'calendar',
events: [
{ id: '1', title: 'Launch', start: '2026-07-01', color: '#3b82f6' },
],
defaultView: 'month',
metadata: { title: 'Product Roadmap' },
},
document.getElementById('cal'),
);
</script>