# UC-016: Custom JS Callbacks **As a** Vaadin application developer, **I want to** define custom JavaScript callbacks for render hooks and constraints **so that** I can customize entry/resource rendering beyond what the Java API offers. **Status:** Implemented **Date:** 2026-03-21 --- ## Scope **Addon module:** addon + addon-scheduler **Related Options:** Various callback options (e.g., `ENTRY_ALLOW`, `SELECT_ALLOW`, `ENTRY_OVERLAP`, render hooks in SchedulerOption) **Related Events:** — --- ## User-Facing Behavior - Developers can pass JavaScript functions as option values - JS callbacks execute client-side for render customization, constraint validation, and formatting - Entry custom properties (`setCustomProperty`) are accessible in JS callbacks - Scheduler render hooks customize resource label/lane rendering --- ## Java API Usage ```java // Custom allow callback calendar.setOption(Option.ENTRY_ALLOW, JsCallback.of("function(dropInfo, draggedEvent) { return dropInfo.start.getDay() !== 0; }")); // Custom overlap callback calendar.setOption(Option.ENTRY_OVERLAP, JsCallback.of("function(stillEvent, movingEvent) { return stillEvent.extendedProps.allowOverlap !== false; }")); // Custom select allow calendar.setOption(Option.SELECT_ALLOW, JsCallback.of("function(selectInfo) { return selectInfo.start.getDay() !== 0; }")); // Scheduler: custom resource label scheduler.setOption(SchedulerOption.RESOURCE_LABEL_CONTENT, JsCallback.of("function(arg) { return { html: '' + arg.resource.title + '' }; }")); // Entry custom properties (accessible in JS callbacks) entry.setCustomProperty("priority", "high"); entry.setCustomProperty("department", "Engineering"); ``` --- ## Entry Render Hooks In addition to constraint callbacks, the addon supports entry rendering hooks via options: ```java // Custom entry content (e.g., HTML rendering) calendar.setOption(Option.ENTRY_CONTENT, JsCallback.of("function(arg) { return { html: '' + arg.event.title + '' }; }")); // CSS class names based on entry properties calendar.setOption(Option.ENTRY_CLASS_NAMES, JsCallback.of("function(arg) { if (arg.event.extendedProps.isUrgent) return ['urgent']; }")); // Post-render setup (e.g., tooltips) calendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.of("function(arg) { arg.el.title = arg.event.title; }")); // Cleanup before removal calendar.setOption(Option.ENTRY_WILL_UNMOUNT, JsCallback.of("function(arg) { /* cleanup */ }")); ``` --- ## Business Rules | ID | Rule | |----|------| | BR-01 | `JsCallback.of(string)` wraps a JS function for client-side execution | | BR-02 | JS callbacks use `new Function()` intentionally for dynamic evaluation | | BR-03 | Custom properties set via `setCustomProperty` are available as `event.extendedProps` in JS | | BR-04 | Entry render hooks: `ENTRY_CONTENT`, `ENTRY_CLASS_NAMES`, `ENTRY_DID_MOUNT`, `ENTRY_WILL_UNMOUNT` | | BR-05 | Scheduler render hooks: `RESOURCE_LABEL_CONTENT`, `RESOURCE_LABEL_CLASS_NAMES`, `RESOURCE_LABEL_DID_MOUNT`, `RESOURCE_LANE_CONTENT`, etc. | | BR-06 | Callbacks must be synchronous (no async/await) | | BR-07 | Native DOM event listeners registered via `addEntryNativeEventListener(eventName, jsCode)` are automatically merged into `ENTRY_DID_MOUNT`. Example: `calendar.addEntryNativeEventListener("click", "console.log('clicked', e.target)")` registers a browser `click` handler on each entry's DOM element. | --- ## Acceptance Criteria - [ ] `ENTRY_ALLOW` callback can accept/reject drops - [ ] `SELECT_ALLOW` callback can accept/reject selections - [ ] Custom properties are accessible in JS callbacks via `extendedProps` - [ ] Scheduler render hooks customize resource rendering - [ ] Invalid JS does not crash the calendar — graceful degradation *(manual verification)* --- ## Tests ### Unit Tests - [ ] `JsCallbackTest` — JsCallback construction, serialization - [ ] `InteractionCallbacksTest` — callback options ### E2E Tests - [ ] `interaction-callbacks.spec.js` — callback behavior --- ## Related FullCalendar Docs - [eventAllow](https://fullcalendar.io/docs/eventAllow) - [selectAllow](https://fullcalendar.io/docs/selectAllow) - [Render Hooks](https://fullcalendar.io/docs/content-injection)