Pathfinderby Commenda
Components

Calendar

Date-only deadlines with month and agenda views, entity filtering and record previews.

Review deadlines across entities, inspect a record without leaving the calendar, and start a filing or task for a specific day.

Month

October 2026

MonthAgenda
Sun
Mon
Tue
Wed
Thu
Fri
Sat

Click a filing to inspect its details. October 13 has five records: 2 more opens all five; choosing a record replaces that list inside the same popup. Escape closes the preview and returns focus to the originating trigger. Today, previous and next navigate the selected month.

The month has five or six weeks. Adjacent-month dates are muted but their events retain their colors. Weekend cells have a quiet background. Today uses the red date badge. At most three chips appear per day.

Choosing the Component

You need to…Use
Review records by month or in a chronological listCalendar
Enter a date, month or date range in a formDatePicker
Sort and filter records with many columnsTable

Calendar owns presentation and interaction. Your application owns records, permissions, status calculations and persistence. Dates represent whole days; time slots, recurrence and drag scheduling are outside this component's contract.

Usage

Example.tsx
import { Calendar, type CalendarEvent } from '@commenda/pathfinder/calendar';

const events: CalendarEvent[] = [
  {
    id: 'vat-q3',
    title: 'VAT return Q3',
    date: '2026-10-20',
    category: { id: 'indirect', label: 'Indirect tax', tone: 'blue' },
    entity: { id: 'de', label: 'Meridian GmbH' },
    status: { label: 'In progress', tone: 'info' },
  },
];

<Calendar
  label="Compliance calendar"
  events={events}
  dateConfig={{ today: '2026-10-13' }}
/>;

Import @commenda/pathfinder/styles.css once in the application. No consumer Tailwind compilation is needed. Interactive callbacks belong in a client component in Next.js App Router.

Agenda

October 2026

MonthAgenda

Oct Tue

Overdue
In progress
Filed
Extended
To do

Oct Tue

Due soon

Oct Wed

Agenda groups the selected month's records by date. Entity flags, category and status remain visible. Status, assignee and action slots retain their alignment when a record has no assignee. Actions are available on hover, keyboard focus and touch. Narrow containers move trailing details to a second line.

Controlled State

October 2026

MonthAgenda

Oct Tue

Application state: 2026-10 · agenda

The text below the example shows application state. Navigate or change view, then use Reset. This is the pattern for URL state, saved preferences or a parent-owned toolbar.

Use defaultValue for internal state with an optional change notification. Use value with onValueChange when the parent owns state. Calendar emits the requested value; it does not override a controlled prop. Supplying both modes is a TypeScript error.

Responsive View

October 2026

MonthAgenda

Oct Tue

Overdue
In progress
Filed
Extended
To do

Oct Tue

Due soon

Oct Wed

The default auto view uses Agenda below 900px of container width and Month at or above it. Choosing Month or Agenda makes that choice persistent. Set a controlled viewConfig.value to auto to restore automatic behavior. An explicitly selected Month view scrolls within its container on narrow screens.

Entity Filtering

October 2026

MonthAgenda

Oct Tue

Overdue
In progress
Filed
Extended
To do

Oct Tue

Due soon

Oct Wed

Empty selected IDs mean all entities. Choose one entity to remove its repeated name from agenda metadata; flags remain. Filter selection survives month and view changes. The optional configuration follows Pathfinder's value/onValueChange or defaultValue pattern. Supply the complete available entity choices and stable IDs.

Categories and Statuses

Category and lifecycle status are independent. The examples use these verified Figma bar modes:

Categorycategory.tone
Direct taxamber
Indirect taxblue
Transfer pricingindigo
Entity compliancepurple
Payrollteal
Customsrose
Otherneutral

status.label and status.tone describe the agenda badge. Optional status.appearance controls the compact record presentation:

AppearanceBehavior
defaultNeutral chip with category bar
overdueCategory bar retained; red status mark with Overdue tooltip
filedMuted category bar and text; green Completed mark
extendedDashed neutral outline

The revised October 12 Figma treatment supersedes older tinted-chip descriptions. The package never infers status from today. For example, an extended deadline can retain an “In progress” badge while using appearance: 'extended'. A flag is an optional React element; Pathfinder gives it optical 12px dimensions. Use the circular country flag assets.

Record Previews and Actions

October 2026

MonthAgenda

Oct Tue

Overdue
In progress
Filed
Extended
To do

Oct Tue

Due soon

Oct Wed

Clicking a record opens its preview. Navigation occurs only through the explicit Open record action. eventConfig.getMenu(event) supplies the existing recursive Dropdown menu contract for record actions. All records retain their stable IDs when filtering or navigating.

October 2026

MonthAgenda

Oct Tue

renderPreview(event) replaces the default metadata body. Calendar retains the accessible popup title, close control and focus return. Applications own authorization and save flows. Keep critical information readable without relying on color or a tooltip.

Create on a Date

October 2026

MonthAgenda
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Click a day background or use Add filing.

Click a day background or its plus affordance to choose an action. A temporary New chip appears while the menu is open; cancellation removes it. Each callback receives { date, entityIds }. Clicking an existing record never invokes creation.

The toolbar uses the first action as its default and puts alternatives in a SplitButton. Toolbar creation uses the supplied business-local today; day creation uses the clicked date, including adjacent-month cells. The app opens the form and persists a new event. Calendar does not insert optimistic records automatically.

API Loading and Recovery

October 2026

MonthAgenda
Loading events…

This example simulates a request, discards obsolete results, and exposes failure/retry. Navigate rapidly or click Simulate API failure. Replace its timer with your query client or fetch and AbortController.

onVisibleRangeChange reports inclusive { start, end, month, view }. Month includes adjacent grid dates; Agenda reports the selected month's first and last dates. Include selected entity IDs in the application query key. Cancel stale requests and only pass results belonging to the current key. Do not turn loading or failed responses into an empty event array without the corresponding stateConfig.

Empty State

October 2026

MonthAgenda
No deadlines match your current entities.

stateConfig.emptyContent explains an empty month or current entity filter. Month retains its date grid so creation remains available. Loading and retryable errors take precedence over empty content.

API Reference

Import CalendarProps, CalendarEvent, CalendarEntity, CalendarView, CalendarTone, CalendarVisibleRange, CalendarAddContext and CalendarAddAction from @commenda/pathfinder/calendar or the package root. The public API is one component with direct configuration props; day cells and popup components are internal.

PropTypeDefault / ownership
labelstringRequired accessible region name
eventsreadonly CalendarEvent[]Required; app owns data and unique IDs
dateConfig.todaystringRequired YYYY-MM-DD business-local date
dateConfig.localestringen-US; dates use Intl formatting
dateConfig.weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 60 (Sunday)
monthConfigSelectionProps<string>Today’s YYYY-MM month
viewConfigSelectionProps<CalendarView>auto; also month or agenda
entityFilterConfigSelection config + entities, optional labelOmitted: no filter; empty IDs: all
eventConfigrenderPreview, onOpen, getMenuDefault metadata preview
addConfig.actionsreadonly CalendarAddAction[]Omitted: read-only calendar
stateConfigisLoading, loadingLabel, error, emptyContentReady
onVisibleRangeChange(range: CalendarVisibleRange) => voidApp-owned requests
classNamestringRoot styling only

Event Records

FieldTypeGuidance
idstringStable and unique across the supplied collection
titlestringFull record name; chips truncate, previews expose it
datestringCanonical YYYY-MM-DD deadline
category{ id, label, tone }Category identity, readable label and one of the seven bar tones
entity{ id, label, flag? }Stable entity identity; optional circular flag element
status{ label, tone?, appearance? }Badge content and independent compact-chip treatment
assigneePersonIdentity{ kind: 'person', userId?, name?, email?, src? }; omission means unassigned

Input order determines event order within each day. Agenda sorts day groups chronologically. The application should sort its records before passing them if a business-specific priority is required.

ConfigFieldsBehavior
monthConfigvalue, onValueChange or defaultValue, optional onValueChangeValues are YYYY-MM
viewConfigSame controlled/uncontrolled shapemonth, agenda or auto
entityFilterConfigSame shape with readonly string[], plus entities, optional labelEmpty IDs means all; omitted config hides the filter

entities is a readonly array of { id, label, flag? }. The app reconciles selected IDs when its available entities change. Calendar filters the supplied event collection by those IDs; it does not fetch missing records.

Record Interactions

eventConfig fieldSignatureWhen to use it
renderPreview(event: CalendarEvent) => ReactNodeReplace default metadata with a domain-specific preview
onOpen(event: CalendarEvent) => voidShow Open record and route to the full record when it is pressed
getMenu(event: CalendarEvent) => DropdownMenuSupply recursive actions; available in Agenda and record previews

An event click opens its preview; it does not call onOpen. Action callbacks receive the same record object you supplied. Check permissions before supplying action items, and apply the same checks in your API.

Creation Config

addConfig.actions is a readonly array of { id, label, onAction }. Its context is:

Example.tsx
type CalendarAddContext = {
  date: string;
  entityIds: readonly string[];
};

The first action is the toolbar default; remaining actions appear in its split menu. Every supplied action appears in the day menu. Omit addConfig for a review-only calendar. An empty action array also hides creation controls.

Loading, Errors and Empty Results

stateConfig fieldTypeBehavior
isLoadingbooleanReplaces the event content with a named loading status; navigation remains usable
loadingLabelstringDefaults to “Loading events…”
error{ message: string; onRetry?: () => void }Displays the message and an optional Retry action
emptyContentReactNodeShown when the selected month/filter has no events

Precedence is loading → error → ready/empty. On a request failure, clear loading and provide the error. Use empty content only for a successful request with no matching records. Do not pass stale results for a new visible range.

Visible Range Callback

Example.tsx
type CalendarVisibleRange = {
  start: string; // Inclusive YYYY-MM-DD
  end: string; // Inclusive YYYY-MM-DD
  month: string; // YYYY-MM
  view: 'month' | 'agenda'; // Effective view, never 'auto'
};

The callback runs after the initial render and when its range or effective view changes. Changing entities alone does not change the date range; include entity state separately in your request key. auto can report Agenda initially and then Month after the container is measured, so request cancellation matters.

Dates are canonical date-only values. No timestamps, locale-formatted strings, UTC-midnight conversions or implicit browser clock. Calendar arithmetic does not shift dates across timezones. The supported range is years 1000–9999; boundary grid slots outside that range are blank. Invalid dates throw a descriptive RangeError; validate API data before rendering.

Keyboard and Accessibility

Key / inputResult
Tab / Shift+TabMove through navigation, filters, event triggers and available day actions
Enter / Space on an eventOpen its preview
Enter / Space on N moreOpen all events for the day
EscapeClose the active popup and restore focus to its trigger
Arrow keys in the view selectorChoose Month or Agenda
Hover / focus a status markShow Completed or Overdue text

Provide an accessible label, meaningful event titles and text status labels. Color is supplementary. Every event remains reachable through its day overflow. The mobile default is Agenda; an explicitly chosen Month view uses internal horizontal scrolling.

Figma Rules and Decisions

  • CALENDAR-001: Shared toolbar and filter state for both views; named navigation controls and month announcements.
  • CALENDAR-002: Outside-month text uses pearl-800 instead of the master’s pearl-600 to meet text contrast. Sunday-first default, five/six rows, 120px nominal days, 4px padding, half-pixel rules.
  • CALENDAR-003: Three chips plus overflow; selecting from a day list replaces its content in one dialog.
  • CALENDAR-004: 20px chips, 3px bar, 12px circular flag, single-line title. The preview exposes full text.
  • CALENDAR-005: Revised neutral fills; separate category and lifecycle presentation.
  • CALENDAR-006: Status tooltip targets are keyboard-focusable siblings, never nested buttons.
  • CALENDAR-007: Agenda retains status104 / avatar24 / actions24 slots; missing assignments do not shift columns.
  • CALENDAR-008: Creation forwards the date and entity IDs; a draft is temporary, not saved data.
  • CALENDAR-009: Enter/Space open previews. Escape/outside dismiss; focus returns to the originating trigger.
  • CALENDAR-010: Month changes are instant for all input methods, including reduced motion. The toolbar never slides.

Month uses table semantics and native buttons, not an incomplete ARIA grid. Tab traverses interactive records and add targets; arrow keys operate the view selector and existing selection/menu primitives. Mobile defaults to Agenda. No dragging, timed-event scheduling or recurrence engine is included.

Sources: Calendar rules, component masters, interaction examples. Revised category modes were verified directly from Figma, including indigo Transfer pricing and teal Payroll.

On this page