MultiDatePick User Guide

Every component, every prop, every gotcha — in the order an admin would meet them.

1. The three components — when to use each

MultiDatePick ships three Lightning Web Components on a shared base. Pick the one that matches your data shape:

multiDatePickDates Dates tier

Simple multi-date selection. Best for RSVPs, attendance, blackout-date entry, holiday calendars.

Component reference →

multiDatePickDateTime Booking tier

Dates plus time slots. Best for classes, appointments, training blocks, daily schedules with morning/afternoon sessions.

Component reference →

multiDatePickBooking Booking tier

Dates + times + resource lookup. Best for room booking, equipment scheduling, multi-resource events, capacity-aware reservations.

Component reference →

Feature comparison

Features cascade upward: anything available on Dates is also available on DateTime and Booking. DateTime adds time. Booking adds resources + capacity on top of that.

Feature Dates
Dates tier
DateTime
Booking tier
Booking
Booking tier
Available on all three components
Date selection
Status colors
Blocked dates
Preload existing records
Edit mode
Recurring patterns
DateTime & Booking only
Time slots
Sub-block records
Booking only
Resource picker
Capacity badges

2. Data shapes — when to use each

Data shape is the combination of three independent choices. Pick any combination — the wrapper supports them all.

Step 1
Time

Dates — no times, just dates.

DateTime / Booking — each record has a start & end time.

Add-on: consolidateTimeSpan — one parent for the full time range, sub-block children for any gaps inside it.

Step 2
Resource

None — Dates / DateTime, or Booking without a resource.

Single resource — Booking with a resource picker dropdown.

Multi-resource — Booking with checkboxes, one record per checked resource.

Step 3
Range

Per-click — each selected date becomes its own record. Five clicks = five records.

Per-range — contiguous dates consolidate into one record with start + end. Requires endDateField.

Worked examples — walk through the 3 questions

For each scenario below, answer 3 questions to land on a data shape. This is the same flow the Setup Wizard walks you through.

Setup Wizard's Shape-pick Q&A page showing the same 3 questions (time / resource / range) with mini data-shape diagrams on each answer card
The Setup Wizard's Walk me through it path asks the same 3 questions in-org — pick an answer card per question and the wizard maps your answers to a data shape.

PTO request

Do you need times? — No, just dates.

Do you need a resource picker? — No resource.

Should adjacent dates consolidate? — Yes — Mon–Fri PTO should be ONE record.

Per-range — one record with start=Mon, end=Fri.

Conference room reservation

Do you need times? — Yes, each booking has start & end.

Do you need a resource picker? — Yes, pick one room.

Should adjacent dates consolidate? — No, each booking is its own record.

Single-resource booking — one record per date × time block, tied to the picked room.

Multi-room training across 3 rooms

Do you need times? — Yes, shared start & end each day.

Do you need a resource picker? — Yes, pick multiple rooms with checkboxes.

Should adjacent dates consolidate? — Yes, the training runs Mon–Fri continuously.

Multi-resource range — one record per room covering the full date range with shared start/end times.

Full-day training with a lunch break

Do you need times? — Yes, 9 AM–5 PM with a lunch gap.

Do you need a resource picker? — No resource.

Should adjacent dates consolidate? — Yes, plus track the lunch gap as a child record.

Parent + sub-blocks (via consolidateTimeSpan) — one parent for the 9 AM–5 PM range, sub-block child for the 12 PM lunch gap.

The grid — every combination

Pick the row that matches your time + resource needs, then choose per-click or per-range based on whether endDateField is mapped. Every cell is a valid configuration.

Time + Resource Per-click
(no endDateField)
Per-range
(endDateField mapped)
Dates
No time. Component: multiDatePickDates
Per-date
1 date → 1 record.
Use for: RSVPs, attendance, daily check-ins.
Per-range
Contiguous dates → 1 record with start + end.
Use for: PTO, travel, multi-night stays.
DateTime
Time block per record. Component: multiDatePickDateTime
Per-block
1 date × 1 time block = 1 record.
Use for: Timesheets, shift segments, training blocks.
Range with shared time block. Contiguous dates with consistent times → 1 record.
Use for: Multi-day training with same start/end each day.
DateTime + consolidateTimeSpan
Parent record + sub-block children for gaps
Parent + sub-blocks
One parent record spans the full time range; gaps inside become sub-block children. (Range is implicit — the consolidation IS the range.)
Use for: Training with lunch breaks, field service routes with travel between stops.
Booking, single resource
One resource picker. Component: multiDatePickBooking
Single-resource booking
1 record per date × time block, tied to the resource.
Use for: Conference rooms, trainer scheduling.
Single-resource range. Contiguous dates with same time on one resource → 1 record per range.
Use for: Multi-night hotel-room reservation, multi-day equipment checkout.
Booking, multi-resource
Resource checkboxes (allowMultipleResources)
Multi-resource booking
1 record per resource × date × time block.
Use for: Parallel team meetings, multi-room training.
Multi-resource range. Contiguous dates with same time across N resources → N records (one per resource).
Use for: Multi-day training booked across 3 rooms simultaneously.
Booking + consolidateTimeSpan
Parent booking + sub-block gap children
Booking parent + sub-blocks. Combines resource lookup with the parent / sub-block pattern.
Use for: Resource booked all day with documented breaks (lab equipment with maintenance windows).

Bottom line: any combination of the 3 steps works. If your scenario doesn't match one of the named patterns, just configure each step independently — the wrapper figures it out.

3. Setup Wizard walkthrough

The Setup Wizard turns a configuration into a reusable Custom Metadata record. Same wizard, same record — place anywhere with a configName reference. Five steps:

Step 0 — Path picker

The wizard greets new admins with three paths: Shape (pick from the 6 shapes above), Full (skip the shape picker and configure every prop manually), or Existing (load a saved config). Pick what fits.

Setup Wizard's landing screen with the three path cards: Walk me through it, Configure all properties, and Existing Configurations
Step 0 — the wizard's path picker. Walk me through it runs the 3-question Q&A; Configure all properties jumps straight to Step 1.

Step 1 — Component Type, Config Name, Label

Pick which component you're configuring (Dates / DateTime / Booking). The Config Name is the developer name of the CMT record — admins reference it via the wrapper's configName property. Label is the human-readable name.

Tier note: If you pick DateTime or Booking but you're on the Dates tier, the wizard shows an info banner. You can still configure the component now — the saved config will start working as soon as you upgrade.

Setup Wizard Step 1 showing the Component Type chooser (Dates / DateTime / Booking) and the Config Name + Label inputs
Step 1 — pick the component, name the config. The Config Name becomes the CMT record's DeveloperName.

Step 2 — Object & Fields

The big one. Pick the related object (e.g. Schedule__c or your own), the Date Field, the Relationship Field back to the parent, and any optional fields (End Date for ranges, Sub-Block fields for parent+sub-block shape).

Setup Wizard Step 2 showing object and field pickers — Related Object, Date Field, Relationship Field, End Date Field, and the Placement chooser for the page surface
Step 2 — field mapping. The wizard reads your org's schema and offers picklists for every dropdown.
All properties reference 84 properties Click to expand — searchable
Property Dates DateTime Booking Type Default Description
showSelectedSummaryBooleantrueWhen ON, displays a summary showing how many dates are selected and which ones.
showInlineBooleanfalseWhen ON, the calendar is always visible without needing to click a button. When OFF, a button opens the calendar in a popup.
modalTitleStringSelect DatesTitle displayed at the top of the calendar modal.
twoMonthViewBooleanfalseWhen ON, shows two side-by-side months for easier range selection. When OFF, shows one month at a time.
calendarSizeStringmediumControls the overall size of the calendar. 'small' for tight spaces, 'medium' for most layouts, 'large' for touch-friendly experiences.
labelStringSelect DatesText shown on the button that opens the date picker. Example: 'Choose Dates' or 'Add Dates'
showDoneButtonInlineBooleantrueWhen ON and Show Inline is enabled, shows a Done button that collapses the calendar to a summary view.
requiredBooleanfalseWhen ON, the user must select at least one date before the Flow can advance to the next screen.
saveButtonLabelStringSaveText on the save button when in Click to Save mode. Example: 'Save Dates', 'Confirm Selection'
weekStartsOnMondayBooleanfalseWhen ON, the calendar week begins on Monday (ISO standard). When OFF, the week begins on Sunday (US standard).
dayHeaderFormatString3Length of day-of-week headers. '3' = SUN MON TUE, '2' = SU MO TU, '1' = S M T.
Selection rules
maxSelectionsInteger0Maximum number of dates a user can select. 0 = unlimited.
disabledDatesString[]Specific dates that cannot be selected (shown greyed out). Use for holidays or blackout dates. Provide as ISO format (YYYY-MM-DD).
allowPastDatesBooleantrueWhen ON, users can select any past date. When OFF, only today and future dates are selectable.
availableDatesString[]When set, ONLY these dates are selectable — all others are greyed out. Provide as ISO format (YYYY-MM-DD). Useful when valid dates come from another source in your Flow.
maxDateDateThe latest date users can select. Dates after this are greyed out.
showRecurringPatternBooleantrueWhen ON, shows a button that lets users quickly select all weekdays, weekends, or specific days of the week up to an end date.
autoJumpToFirstAvailableBooleanfalseWhen ON and 'Only These Dates Are Selectable' is set, the calendar automatically opens to the month of the first available date.
defaultDatesString[]Dates that are already selected when the calendar opens. Provide as ISO format (YYYY-MM-DD).
minDateDateThe earliest date users can select. Dates before this are greyed out.
Object & Fields
endDateFieldStringAPI name of an End Date field on the child object. When set, adjacent selected dates are consolidated into a single record with start and end dates instead of one record per date. Example: End_Date__c
staticRecordIdStringEdge case: hardcode a Record Id to pin this calendar to a single parent record. Works on Record Page, App Page (requires static id), Home Page (requires static id), and Experience Site (requires static id). On a Record Page, leave blank — the page's record is auto-injected.
relationshipFieldApiNameStringAPI name of the lookup field on the child object that links back to the parent record. Example: Account__c, Contact__c, Order__c
appendDateTimeToNameBooleantrueWhen ON, appends the date to the record name. Example: 'PTO Day' becomes 'PTO Day - Mar 31, 2026'.
defaultRecordNameStringPre-fills the record name input. Users can change it at runtime. Example: 'PTO Day', 'Team Meeting'.
dateFieldApiNameStringAPI name of the Date field on the child object that stores the selected date. Example: Event_Date__c, Start_Date__c
relatedObjectApiNameStringAPI name of the object where each selected date is saved as a record. Example: Appointment__c, Schedule_Entry__c. Required for Click to Save.
recordIdStringWhen set, the component runs in Click to Save mode and writes child records linked to this parent. Pass in a record Id from a Get Records or recordCreate output (e.g. {!recordVar.Id}). Leave blank to use the standard parser+loop+create pattern.
recordNameFieldStringAPI name of a text field on the child object where a record label is saved. When set, a text input appears for users to enter a label.
parentRecordIdFieldStringOnly needed when this component lives on a DIFFERENT object's record page than the parent. Enter the API name of the lookup field that points to the real parent. Leave blank when this component is on the parent object's page.
Status & Edit
statusColorDisplayStringcalendarWhere status colors are rendered. For the Dates component, only 'calendar' is available — date cells on the calendar are colored by their status.
editRecordDisplayStringComma-separated keywords controlling which fields show in the edit mode record list and in what order. Keywords: name, status, time, date, resource. Default when blank: name, status, time. Example: name, date, status
statusFieldLabelStringOptional display label for the status dropdown shown to end users. Do NOT enter a field API name here — this is a display label only. If blank, the component auto-humanizes the Status Field API name.
hoverFieldsStringComma-separated list of field API names to display when hovering over a calendar date that has existing records. Fields are queried from the Child Object. Supports relationship fields. Only shows data when existing records are loaded (via Load Existing Dates). Example: Name, Status__c, Notes__c. Leave blank to disable hover popovers.
enableEditModeBooleantrueWhen ON, users can click existing dates to edit the date value or status, or delete the record. Requires Status Field AND Status Colors to be configured.
hideBookingsWithStatusStringComma-separated list of status values whose records are hidden from the calendar. Hidden records are excluded from visual rendering. Records remain in Salesforce. Requires Status Field. Example: Cancelled, Rejected
statusColorsStringComma-separated mapping of status values to hex colors. Format: Value:#hex. Status colors are shown on calendar date cells. Requires Status Field. Example: Confirmed:#0176d3, Tentative:#fbbf24, Pending:#60a5fa, Cancelled:#a1a8b5
editButtonLabelStringCustom label for the Edit Mode toggle button. Defaults to 'Edit Dates' if left blank.
Time slots
timeDisplayModeStringgridHow time is presented. 'grid' (default): visual slot grid where users click or drag to select time blocks. 'dropdown': lightning-input time pickers. Use 'Allow Different Times Per Date' to control shared vs. per-date pickers in dropdown mode.
groupTimeSlotsByPeriodBooleanfalseWhen ON, time slots are grouped into Morning, Afternoon, and Evening sections. When OFF (default), shows a flat grid. Only applies when Time Display Mode is 'grid'.
endTimeFieldStringAPI name of a Time field on the child object for the slot end time. Example: End_Time__c
enableEndTimeBooleantrueWhen ON, shows a separate End Time dropdown alongside Start Time. Outputs both startTime and endTime in the JSON output. Only applies in dropdown mode (Time Display Mode = 'dropdown'). Has no effect in grid mode.
timeIntervalInteger30Minutes between time options. Options: 15, 30, or 60. Example: 30 shows 9:00, 9:30, 10:00...
startTimeFieldStringAPI name of a Time field on the child object for the slot start time. Example: Start_Time__c
minTimeStringEarliest time shown in the time selector. Use 24-hour format (HH:mm). Examples: 08:00 = 8:00 AM, 13:00 = 1:00 PM. Leave blank to start at 12:00 AM.
maxTimeStringLatest time shown in the time selector. Use 24-hour format (HH:mm). Examples: 17:00 = 5:00 PM, 20:00 = 8:00 PM. Leave blank to end at 11:30 PM.
allowDifferentTimesBooleanfalseWhen ON and Time Display Mode is 'dropdown', each date gets its own time picker (grouped by week). When OFF, all dates share one time. Has no effect when Time Display Mode is 'grid'.
Resource & Booking
disableTimeSlotGridBooleanfalseWhen ON, hides the time slot grid for full-day booking scenarios where only the date matters. When OFF (default), shows the time slot grid for granular time-based booking.
businessHoursStartFieldStringAPI name of the Time field on the resource object defining when it becomes available each day. Example: Business_Hours_Start__c (set to 08:00:00.000Z for 8:00 AM). Leave blank to use time slots for the full configured interval.
allowMultipleResourcesBooleanfalseWhen ON, users can select multiple resources with checkboxes and book all of them simultaneously. The time grid shows only slots available for ALL selected resources. Example: Book a room AND a projector at the same time.
businessHoursEndFieldStringAPI name of the Time field on the resource object defining the last available time each day. Example: Business_Hours_End__c (set to 18:00:00.000Z for 6:00 PM).
resourceBookingObjectStringAPI name of the object where booking records are created. One record per date per resource. Example: Room_Booking__c, Equipment_Reservation__c
bookingResourceFieldStringAPI name of the lookup field on the booking object that points to the resource. Example: Room__c (lookup from Room_Booking__c to Room__c)
resourceBookButtonLabelStringBookText on the button that confirms the booking. Example: 'Book Now', 'Reserve', 'Confirm Booking'
resourceNameFieldStringNameAPI name of the field containing the resource's display name. Usually 'Name'.
resourceFilterFieldStringAPI name of a field on the resource object used to limit which resources appear in the picker. Pair with Resource Filter Value. Use ';' to combine multiple fields (AND). Examples: 'Active__c' (one boolean field), 'Type__c' (one picklist), 'Type__c;Building__c' (TWO fields combined with AND). Leave blank to show every resource.
resourceObjectApiNameStringAPI name of the object storing your bookable resources. Each record = one bookable resource shown in the dropdown. Example: Room__c, Equipment__c, Vehicle__c, Staff__c
bookingDateFieldStringAPI name of the Date field on the booking object. Must be a Date type (not DateTime). Example: Booking_Date__c
bookingStartTimeFieldStringAPI name of the Time field on the booking object for the start time. Example: Start_Time__c. Leave blank for date-level bookings without time slots.
showAvailabilityCountBooleantrueWhen ON, shows availability details in the resource panel.
resourceFilterValueStringValue(s) the filter field must equal. ',' between values within ONE field = OR (IN clause). ';' between values = AND across multiple fields (must match the field count in Resource Filter Field). Examples: 'true' — Active=true. 'Conference Room' — Type=Conference Room. 'North,South' — Building IN North or South. 'Conference Room;North' — Type=Conference Room AND Building=North. 'Conference Room;North,South' — Type=Conference Room AND Building IN North or South.
bookingEndTimeFieldStringAPI name of the Time field on the booking object for the end time. Example: End_Time__c. The system calculates end time based on selected slots.
Sub-block
consolidateTimeSpanBooleanfalseWhen ON, selected time slots output as a single span from first slot start to last slot end. Gaps between selected slots auto-turn orange and are tracked as sub-blocks. Use for scheduling scenarios where you need a full shift span (e.g. 9 AM-5 PM) while separately tracking breaks. Only applies in grid mode.
subBlockEndTimeFieldStringEnd Time field on the sub-block object. Example: Break_End__c. Required when Sub-Block Object is set.
subBlockNameFieldStringText field on the sub-block object to store a label. Example: Break_Name__c. Required when Sub-Block Object is set.
subBlockModeButtonLabelStringWhen set, adds a toggle button letting users manually mark slots as sub-blocks (orange). Useful for sub-blocks at the edge of the work span. Leave blank to use auto-orange only. Example: 'Mark as Break', 'Mark as Lunch'. Requires Consolidate Time Span to be ON.
subBlockStartTimeFieldStringStart Time field on the sub-block object. Example: Break_Start__c. Required when Sub-Block Object is set.
subBlockObjectApiNameStringAPI name of the child object for sub-block records. Example: Work_Break__c. Requires Consolidate Time Span to be ON and Click to Save mode (Parent Record Id set).
showSubBlockButtonBooleanfalseWhen ON, displays the sub-block toggle button in the time grid header. Requires Consolidate Time Span to be ON and Sub-Block Button Label to be set.
subBlockDateFieldStringDate field on the sub-block object. Example: Break_Date__c. Required when Sub-Block Object is set.
subBlockParentLookupFieldStringLookup field on the sub-block object linking to the parent record. Example: Shift__c. Required when Sub-Block Object is set.
Conflict detection
conflictBehaviorStringblockControls what happens when selected dates have time conflicts with existing records. 'block' (default): save is blocked and conflicting dates are highlighted. 'skip': save proceeds but conflicting dates are skipped. 'allow': no conflict checking. Only applies in grid-shared mode (Time Display Mode='grid' + Allow Different Times Per Date=OFF).
conflictLookAheadDaysInteger360Number of days ahead to check for time slot conflicts and load availability. Default: 360. Reduce for better performance on high-volume objects.
Blocked dates
blockedDatesSourceObjectStringAPI name of an object to query for dates that should be blocked from selection. Example: Public_Holiday__c
blockedDatesFilterFieldStringOptional: lookup field on the blocked object to filter results by the current record. Requires Blocked Dates Object and Blocked Dates Date Field. Leave blank to block globally.
blockedDatesDateFieldStringAPI name of the Date field on the blocked dates object. Requires Blocked Dates Object to be set.
Preload
preloadModeStringeditableControls how loaded dates appear. Only applies when Load Existing Dates is ON. 'editable': dates are selected and can be changed. 'readonly': dates appear greyed out and cannot be removed.
preloadExistingDatesBooleantrueWhen ON, queries existing child records and shows their dates in the calendar on load. Requires Child Object, Date Field, and Relationship Field.
Outputs
selectedDatesWithTimesJsonStringOUTPUT: JSON string with each date and its selected time. Pass to MultiDatePickParser to loop through in your Flow.
selectedDatesString[]OUTPUT: Array of all selected dates in ISO format (YYYY-MM-DD). Use this in your Flow to create records or pass to the next screen.
bookingConflictDatesString[]OUTPUT: List of dates where bookings could not be created due to conflicts with existing reservations.
bookingSuccessCountIntegerOUTPUT: Number of booking records successfully created. Use in your Flow to show a confirmation message.
outputAsJsonBooleanfalseWhen ON, populates the Date Ranges JSON output with consecutive dates grouped into ranges. Required if you want to use the MultiDatePickParser action to loop through ranges.
Other
selectedDateRangesJsonStringOUTPUT: JSON of consecutive dates grouped into ranges. Only populated when 'Output Date Ranges as JSON' is ON. Pass to MultiDatePickParser to loop in Flow.

Step 3 — Resource & Capacity (Booking only)

Pick the Resource object, Capacity field, Business Hours fields, and (optional) Resource Filter to scope the picker (e.g. Active__c=true). The Dates and DateTime components grey out this step.

Setup Wizard Step 3 — Resource object, Capacity Field, Business Hours fields, and Resource Filter inputs (Booking component only)
Step 3 — only visible when Component Type = Booking. Resource Filter accepts SOQL-style WHERE syntax to scope the resource picker.

Step 4 — Status & Display

Status Field (for color-coding), Status Colors mapping (e.g. Confirmed:#0176d3, Tentative:#fbbf24), Edit Mode toggle, display options, sub-block button label.

Setup Wizard Step 4 — Status Field, Status Colors mapping with color swatches, Edit Mode toggle, and other display options
Step 4 — the Status Colors input auto-fetches picklist values from your Status Field. Each row gets a color swatch.

Step 5 — Constraints & Behavior

Max selections, allow past dates, recurring pattern, blocked dates source, conflict look-ahead days, preload mode.

Setup Wizard Step 5 — Max Selections, Allow Past Dates toggle, Recurring Pattern toggle, Blocked Dates Source, Conflict Look-Ahead Days, and Preload Mode
Step 5 — final guardrails. Defaults work for most cases — only touch what you need to restrict.

Save & deploy

Click Save Configuration. The wizard fires an Apex deploy that creates the Custom Metadata Type record. Wait ~30–60 seconds for deploy to complete. Optionally add a description via the post-save card.

Setup Wizard's Import / Export tab showing a textarea for pasting a JSON config and the Save Description card after import
Import / Export tab — paste a JSON config to deploy the same setup elsewhere. After save, an optional description card appears.
Setup Wizard's Existing Configurations tab listing saved CMT configs with their component type, label, and description
Existing Configurations tab — saved configs appear here. Click one to edit or export.

4. Click to Save vs Flow-Managed Save

The wrapper supports two persistence patterns. Pick the one that fits where you're placing it:

Click to Save

The wrapper writes records itself. Set four props and the wrapper's own Save button appears in its footer. Click it, and an Apex insert creates the child records directly. No downstream Flow actions, no custom Apex.

When to use: Record Pages, App Pages, Home Pages, Experience Sites — anywhere the wrapper has a parent record to attach to.

Flow-Managed Save

The wrapper emits selections as JSON output. You build the persistence yourself with downstream Flow actions — typically the bundled Parse Date Entries from JSON action plus your own Record Create / Apex Action elements.

When to use: Flow Screens where you want full control over how / when / where the records get written. Common for multi-step approval flows, conditional record creation, complex validation.

Click to Save — the 4 props

Set these on the wrapper (the Setup Wizard does it for you). When all four are populated, the Save button appears:

  • relatedObjectApiName — the child object that records get inserted into
  • dateFieldApiName — the Date field on that object
  • relationshipFieldApiName — the lookup back to the parent record
  • recordId (auto-injected on Record Pages) or staticRecordId (hardcoded for App Page / Home Page / Experience Site surfaces, which don't get a record context)
Two-button UX in Flow Screens: when Click to Save is enabled inside a Flow, two click actions exist on the screen. The wrapper's Save button commits records to the database. The Flow's Next button just advances the screen — it does NOT trigger the save. Users click Save first, then Next.

Flow-Managed Save — the output props

Leave the four Click-to-Save props blank. The wrapper hides its Save button and emits selections through these Flow output variables:

  • selectedDates — Text collection of ISO date strings (YYYY-MM-DD)
  • selectedDateRangesJson — JSON of grouped contiguous ranges
  • selectedDatesWithTimesJson — JSON of dates with per-date times (DateTime only)
  • bookingSuccessCount / bookingConflictDates — Booking-specific outputs after the wrapper's own save runs (only relevant if you mix the two modes)

Use the bundled Parse Date Entries from JSON invocable action to convert the JSON into a Flow-loopable MultiDatePickEntryCollection with .data[] of MultiDatePickEntry records (fields: fromDate, toDate, startTime, endTime, resourceId). Loop over .data, do whatever persistence pattern fits.

Additive-only save (applies to Click to Save)

By design, saveDateRecordsAdditive only INSERTs new dates — it never deletes existing records when the user deselects a date. To delete, admins use the standard Salesforce related-list UI on the parent record. This prevents accidental data loss when an admin clicks the wrong date.

5. Status colors & edit mode

Status colors

Map any picklist field on your child object to colors. The wrapper paints the calendar (and grid, if you choose) accordingly. Configure:

  • statusField = Status__c (or your picklist API name)
  • statusColors = Confirmed:#0176d3, Tentative:#fbbf24, Pending:#60a5fa, Cancelled:#a1a8b5
  • statusColorDisplay = calendar, grid, or both
  • hideBookingsWithStatus = Cancelled (CSV) to suppress those records from the calendar AND capacity counts

Edit mode

Set enableEditMode=true. The wrapper shows an Edit Dates button. Click it to toggle into edit mode, where:

  • Existing records render as cards with their date and current status visible
  • Click a date in the calendar to add it to the edit set
  • Change a record's date or status — the wrapper updates the database
  • Delete a record with a two-click confirm pattern (prevents accidents)

The status field stays in sync with the database after every edit.

Booking component with status colors active on the calendar (Confirmed slots in blue, Tentative in yellow) and the Edit Mode toggle showing the Edit Dates button
Status colors paint the calendar by picklist value. Edit Mode adds the Edit Dates button — click it to revise existing records inline.

6. Resource booking (Booking component only)

Single-resource mode

The wrapper renders a resource picker dropdown. Admins pick one resource, the time-slot grid loads with that resource's bookings + capacity. Each booked slot shows an X/Y capacity badge.

Multi-resource mode

Set allowMultipleResources=true. The picker becomes a checkbox list. Multiple checked resources show a combined capacity grid — sum of all bookings across selected resources, sum of all capacities.

Booking component in multi-resource mode with two resources checked, showing a combined capacity grid with X/Y badges on each time slot
Multi-resource mode — checkbox picker on the left, combined capacity grid on the right. Each badge shows current bookings over total capacity across the checked resources.

Capacity aggregation modes

The capacityAggregation property controls the multi-resource math:

  • Combined (default) — sum bookings + sum capacities. Example: 2 conference rooms each holding 5 = 0/10 capacity total.
  • Distinct — count unique events (records sharing date+startTime+endTime across resources = ONE event). Uses MAX single-resource capacity. Example: a class booked across 4 rooms simultaneously reads as 1/5, not 4/20.

Conflict detection

conflictLookAheadDays controls how many days ahead the LWC scans for overlapping bookings. conflictBehavior controls what happens when conflicts are found: block (refuse to save), warn (toast then save), or skip (insert non-conflicting, skip the rest, report conflicts in bookingConflictDates).

7. Common gotchas (FAQ)

Real questions admins have hit. Skim these BEFORE filing a support ticket.

I see no calendar — just an amber banner
You have a component-type mismatch or parent-type mismatch. The banner explains what's wrong: either the CMT config was saved for a different component (e.g. a Dates config loaded into a DateTime wrapper), or the wrapper is on the wrong-object record page for the configured relationshipField. Fix the config or move the placement.
Past dates aren't being disabled even with allowPastDates=false
In Flow Builder, explicitly set the prop to {!$GlobalConstant.False} — don't rely on the JS default. Salesforce Flow passes null for unset Boolean props, which doesn't trigger the wrapper's "false" branch the way you'd expect.
My status colors aren't applying
Three things to check: (a) is statusField the exact picklist API name (case-sensitive, no quotes around the name)? (b) Does statusColors use the format Status:#hex, Status:#hex with NO quotes around values? Admins sometimes paste 'Confirmed':'#0176d3' — that breaks the parse silently. (c) Is the picklist value actually populated on the records?
The wrapper saves but records have wrong field values
Check recordNameField — if you mapped a long-text field, the wrapper writes the auto-generated name there but the field may be too short. Also check appendDateTimeToName: if ON, the wrapper appends the selected date/time to the record name — surprising if you didn't expect it.
How do I hide Cancelled records from the capacity grid?
Set hideBookingsWithStatus=Cancelled (or comma-separated list like Cancelled,Rejected). This filters Cancelled records from BOTH the calendar AND the capacity count.
The edit mode toggle isn't appearing
Edit mode requires enableEditMode=true AND a configured statusField. If either is missing, the toggle stays hidden.
I need a resource filter (only show conference rooms, not equipment)
Booking has resourceFilterField + resourceFilterValue. Single value: Active__c=true. IN-clause: Building__c=North,South. AND across fields: Type__c;Active__c=Conference Room;true.
Time selection mode in DateTime keeps reverting to shared
Two props can conflict: legacy timeSelectionMode and new timeDisplayMode. The setter ordering matters — timeDisplayMode='grid' wins per the priority guard, but if you set timeSelectionMode='shared' in App Builder and the LWC's setter order processes shared first, the legacy value can briefly override. Use timeDisplayMode exclusively.
How do I migrate from JSON output to auto-save?
Set recordId + relatedObjectApiName + dateFieldApiName + relationshipFieldApiName. Remove the downstream Apex action that parsed the JSON. The wrapper's own Save button now writes records directly.
I get a "AuraHandledException" but no detail message
Open browser DevTools → Console. Look for [MDP:ERROR]-prefixed logs. The wrapper always logs the underlying exception detail there, even when AuraHandledException strips it from the UI toast.

8. Object & field mapping

Each component page has the full Object/Field Mapping diagram. Quick links:

Each diagram shows what wrapper prop maps to what object/field. The wrapper is fully object-agnostic — the bundled MDP_* object/field names are just defaults. Point any wrapper prop at any custom object with the right field shape.

9. Apex sample code

Reading selectedDates in a Flow

Use the bundled Parse Date Entries from JSON invocable action to convert the wrapper's JSON output into a Flow-loopable collection.

// Flow:
//   Screen with multiDatePickDateTime, outputs selectedDatesWithTimesJson
//   Action: Parse Date Entries from JSON, input = the JSON string
//   Output: MultiDatePickEntryCollection with .data[] of MultiDatePickEntry
//   Loop over .data, access .fromDate, .toDate, .startTime, .endTime per entry

Rollup MIN/MAX child dates to a parent field

A Record-Triggered Flow on the child object can roll up MIN/MAX dates to the parent. Example for Schedule__c rolling up to Event__c.Start_Date__c / End_Date__c:

trigger MDPScheduleRollup on Schedule__c (after insert, after update, after delete) {
    Set<Id> eventIds = new Set<Id>();
    if (Trigger.new != null) {
        for (Schedule__c s : Trigger.new) if (s.Event__c != null) eventIds.add(s.Event__c);
    }
    if (Trigger.old != null) {
        for (Schedule__c s : Trigger.old) if (s.Event__c != null) eventIds.add(s.Event__c);
    }
    if (eventIds.isEmpty()) return;

    Map<Id, Date> minByEvent = new Map<Id, Date>();
    Map<Id, Date> maxByEvent = new Map<Id, Date>();
    for (AggregateResult ar : [
        SELECT Event__c eventId, MIN(Schedule_Date__c) minD, MAX(Schedule_Date__c) maxD
        FROM Schedule__c
        WHERE Event__c IN :eventIds
        GROUP BY Event__c
    ]) {
        Id eid = (Id) ar.get('eventId');
        minByEvent.put(eid, (Date) ar.get('minD'));
        maxByEvent.put(eid, (Date) ar.get('maxD'));
    }

    List<Event__c> toUpdate = new List<Event__c>();
    for (Id eid : eventIds) {
        toUpdate.add(new Event__c(Id = eid,
            Start_Date__c = minByEvent.get(eid),
            End_Date__c = maxByEvent.get(eid)));
    }
    Database.update(toUpdate, false);
}

Replace Schedule__c / Event__c / Schedule_Date__c / etc. with your own schema.

10. Security & accessibility

  • AppExchange Security Reviewed. The package passes Salesforce's Security Review and the sf code-analyzer AppExchange + Recommended:Security rule sets with zero violations.
  • FLS-aware: every Apex method validates object + field access before SOQL/DML via validateObjectAndFieldAccess. All DML runs under Database.insert(records, AccessLevel.USER_MODE) so user permission checks are enforced at the database layer, not just the controller.
  • Accessibility: WCAG 2.1 Level A/AA tested with axe-core. Full VPAT 2.5 at multidatepick.com/accessibility.html.
  • 9 built-in languages: English, Spanish, French, German, Japanese, Hindi, Portuguese (Brazil), Italian, Chinese (Simplified).

11. Questions or bugs?

Found a gap in this guide, or something broken in the package? We want to hear about it.

Email: support@multidatepick.com