Skip to content

FRD: Meeting Scheduler

Document Summary

FieldDetails
Feature NameMeeting Scheduler
StatusDraft
OwnerDavid Holmes
ContributorsDesign, Engineering
Target Releasev2.0.0 (P2)
Related LinksRoadmap item #55
Last Updated2026-05-26

Introduction

Overview

Meeting Scheduler is a compact form widget that composes DatePicker, Select, and Button to let users schedule a meeting by selecting a date, time, and duration. It produces a structured payload with validation and is designed for SaaS applications that need a simple scheduling form (e.g., book-a-call, schedule a demo). Unlike the Availability Picker (#54) which handles multi-day slot selection, this widget focuses on scheduling a single meeting with form-level validation.

Goals

  • Deliver a <MeetingScheduler> component with date, time, duration, and optional title fields.
  • Compose existing DatePicker, Select, and Button primitives.
  • Validate required fields and produce a structured scheduling payload.
  • Ship Storybook stories with realistic scheduling scenarios.

Non-Goals

  • Multi-participant availability checking or conflict detection.
  • Calendar integration (Google Calendar, Outlook, iCal).
  • Recurring meeting setup.
  • Video conferencing link generation.
  • Room/resource booking.

Scope

In Scope

AreaDescription
Component<MeetingScheduler> form with date, time, duration fields
Date FieldDatePicker for selecting the meeting date
Time FieldSelect dropdown for choosing a start time
Duration FieldSelect dropdown for meeting length
Title FieldOptional text input for meeting title/subject
ValidationRequired field validation with inline errors
PayloadonSchedule fires with structured { date, time, duration, title }
StatesInitial, validation errors, scheduling (loading), error
StoriesStorybook stories for scheduling flow, validation, and states

Out of Scope

AreaReason
Multi-participant schedulingApplication-layer concern
Calendar integrationApplication-layer concern
Recurring meetingsSeparate feature
Video link generationApplication-layer concern
Time zone selectorConsumer handles timezone; can be added later

Users and Pain Points

User Groups

UserDescriptionNeeds
DevelopersEngineers building scheduling featuresA ready-made scheduling form using DS primitives
DesignersDesign-system consumersConsistent scheduling form UX
End UsersPeople booking meetings or callsSimple, clear scheduling with validation feedback

Pain Points

UserPain PointImpact
DevelopersAssembling DatePicker + time Select + duration Select + validation logic for each scheduling UIRepeated boilerplate, inconsistent forms
End UsersScheduling forms that allow submission of incomplete data (missing time, invalid date)Failed bookings, frustration

Definitions

TermDefinition
Meeting SchedulerA form widget for selecting date, time, and duration to schedule a single meeting
DurationThe length of the meeting in minutes (e.g., 15, 30, 45, 60, 90)
Schedule PayloadThe structured data object passed to onSchedule

Current State

Existing Behavior

The design system provides DatePicker for date selection and Select for dropdown choices. There is no combined scheduling form that assembles these with time/duration options and validation.

Current Limitations

  • No scheduling-form widget or pattern.
  • Time selection requires a custom Select with generated time options.
  • Duration options must be configured from scratch.
  • Validation for scheduling fields is left to consumers.

Existing Workarounds

  • Developers build scheduling forms ad hoc with raw DatePicker, Select, and custom validation.

Proposed Solution

Summary

Introduce <MeetingScheduler> that renders a compact form with a DatePicker for the date, a Select for start time (auto-generated from timeStart/timeEnd/interval config), a Select for duration (from durations array), an optional title input, and a Schedule button. The form validates required fields and fires onSchedule with a structured payload.

Key Capabilities

  • Date selection via DatePicker with configurable min/max dates.
  • Time selection via Select with auto-generated options from time range and interval.
  • Duration selection via Select with configurable options.
  • Optional meeting title/subject field.
  • Required-field validation with inline errors.
  • Schedule button with loading state.

User Experience

Users see a compact form. They pick a date, select a start time from a dropdown, choose a duration, optionally enter a title, and click Schedule. If any required field is empty, inline errors appear. During submission, the button shows a loading spinner.

Developer Experience

<MeetingScheduler
onSchedule={({ date, time, duration, title }) => {
bookMeeting({ date, time, duration, title });
}}
timeStart="08:00"
timeEnd="18:00"
interval={30}
durations={[15, 30, 45, 60]}
minDate="2026-06-01"
/>

Requirements

IDRequirementPriorityNotes
FR-001MeetingScheduler renders date, time, and duration fields with Schedule buttonMust-
FR-002Time options are auto-generated from timeStart, timeEnd, and intervalMust-
FR-003Validation prevents submission when date, time, or duration is missingMust-
FR-004onSchedule fires with structured payloadMust-
FR-005Optional title/subject fieldShould-
FR-006Schedule button shows loading state during async submissionShould-

Priority Definitions

PriorityMeaning
MustRequired for this feature to ship.
ShouldImportant, but can be deferred if needed.
CouldNice to have. Not required for initial release.

Functional Requirements

IDRequirementUser BenefitPriority
FUNC-001DatePicker renders for date selection with optional minDate/maxDate boundsConstrained date selectionMust
FUNC-002Time Select populates options from timeStart to timeEnd at interval-minute incrementsNo manual time option listsMust
FUNC-003Duration Select populates from durations array (e.g., [15, 30, 45, 60]) with human-readable labelsClear duration choiceMust
FUNC-004Title input is a single-line text fieldMeeting contextShould
FUNC-005Clicking Schedule validates all required fields; shows inline errors for empty fieldsPrevents incomplete submissionsMust
FUNC-006onSchedule receives { date: string; time: string; duration: number; title?: string }Typed, structured payloadMust
FUNC-007onSchedule can return a Promise; button auto-enters loading state until resolvedLoading feedbackShould
FUNC-008Past dates are disabled in the DatePicker when disablePast is truePrevents scheduling in the pastShould

Non-Functional Requirements

IDRequirementCategoryPriority
NFR-001Form renders in under 20msPerformanceMust
NFR-002All fields and button are keyboard-navigable in tab orderAccessibilityMust
NFR-003Works in light and dark themesThemingMust
NFR-004No new runtime dependenciesMaintainabilityMust

API / Interface Requirements

Public API

NameTypeDescriptionRequired
onSchedule(payload: SchedulePayload) => void | Promise&lt;void&gt;Schedule callbackYes
timeStartstringStart of available time range (HH:MM, 24h)No (default: "08:00")
timeEndstringEnd of available time range (HH:MM, 24h)No (default: "18:00")
intervalnumberTime slot interval in minutesNo (default: 30)
durationsnumber[]Available duration options in minutesNo (default: [15, 30, 45, 60])
minDatestringEarliest selectable date (YYYY-MM-DD)No
maxDatestringLatest selectable date (YYYY-MM-DD)No
disablePastbooleanDisable dates before todayNo (default: true)
showTitlebooleanShow the title/subject fieldNo (default: true)
onCancel() => voidCancel callbackNo
classNamestringAdditional CSS classesNo

SchedulePayload Type

interface SchedulePayload {
date: string; // YYYY-MM-DD
time: string; // HH:MM
duration: number; // minutes
title?: string;
}

Example Usage

import { MeetingScheduler } from "@/components/ui/meeting-scheduler";
<MeetingScheduler
onSchedule={async ({ date, time, duration, title }) => {
await api.createMeeting({ date, time, duration, title });
}}
timeStart="09:00"
timeEnd="17:00"
interval={30}
durations={[30, 60, 90]}
disablePast
/>

API Notes

  • Time options auto-generate: "09:00", "09:30", "10:00", … "17:00" for the example above.
  • Duration labels auto-format: 30 -> “30 min”, 60 -> “1 hour”, 90 -> “1h 30m”.
  • onSchedule returning a Promise auto-manages loading state.

Accessibility Requirements

IDRequirementNotes
A11Y-001All form fields have associated &lt;label&gt; elementsStandard form a11y
A11Y-002DatePicker, time Select, and duration Select are keyboard-operableDelegates to existing component a11y
A11Y-003Inline validation errors linked to fields via aria-describedby-
A11Y-004Schedule button disabled state conveyed to screen readersaria-disabled
A11Y-005Loading state sets aria-busy="true" on the form-

Checklist

  • Keyboard support is defined.
  • Focus behavior is defined.
  • Screen reader behavior is defined.
  • Color contrast requirements are met.
  • Reduced motion behavior is considered.
  • Semantic HTML expectations are documented.
  • ARIA usage is defined only where needed.

Content and Documentation Requirements

IDRequirementLocationPriority
DOC-001Storybook docs page with overview and props tableStorybookMust
DOC-002”When to use / When not to use” guidanceStorybook docsMust
DOC-003Stories for default form, custom time ranges, validation errors, and loadingStorybookMust

Dependencies

DependencyTypeOwnerStatusNotes
DatePickerEngineeringDesign SystemReadyDate field
SelectEngineeringDesign SystemReadyTime and duration dropdowns
ButtonEngineeringDesign SystemReadySchedule and cancel buttons
Design tokensDesignDesign SystemReady-

Risks and Tradeoffs

Risk / TradeoffImpactMitigation
No timezone selectorUsers may schedule in wrong timezoneDocument that consumer should add timezone display; add optional timezone label prop
No availability conflict detectionUsers may double-bookApplication-layer concern; document that consumer should pre-filter available times
Auto-generated time options may produce many options for small intervalsLong dropdown listUse 30-min default; consumer can increase interval

Open Questions

IDQuestionOwnerStatusResolution
Q-001Should a timezone selector be included?David HolmesOpen
Q-002Should the time Select support searching/filtering for long lists?David HolmesOpen
Q-003Should custom duration input be supported beyond the preset list?David HolmesOpen

Acceptance Criteria

IDCriteriaRelated Requirement
AC-001DatePicker, time Select, and duration Select render in the formFR-001
AC-002Time options auto-generate from timeStart/timeEnd/intervalFR-002, FUNC-002
AC-003Submitting with empty required fields shows inline errorsFR-003, FUNC-005
AC-004onSchedule fires with correct structured payloadFR-004, FUNC-006
AC-005Title field renders when showTitle is trueFR-005
AC-006Loading state displays during async submissionFR-006, FUNC-007
AC-007Past dates are disabled when disablePast is trueFUNC-008
AC-008All Storybook stories render without errorsDOC-003
AC-009Component passes axe accessibility auditNFR-002

LLM Handoff Instructions

Expected LLM Behavior

  • Follow the requirements and acceptance criteria in this document.
  • Do not expand scope beyond the In Scope section.
  • Respect the Out of Scope section.
  • Use DatePicker for date selection, Select for time and duration, Button for schedule/cancel.
  • Auto-generate time options using a loop from timeStart to timeEnd at interval increments.
  • Auto-format duration labels (e.g., 60 -> “1 hour”).
  • Implement required-field validation with inline error messages.
  • Place stories under the SaaS Widgets Storybook section.

LLM Should Not

  • Add calendar integration.
  • Build multi-participant scheduling.
  • Add recurring meeting support.
  • Modify existing DatePicker or Select components.

Decision Log

DateDecisionReasonOwner
2026-05-26Single-meeting form rather than multi-slot selectionMeetingScheduler complements AvailabilityPicker; each has a distinct use caseDavid Holmes
2026-05-26Auto-generate time options from range/interval configReduces consumer boilerplate; ensures consistent time formattingDavid Holmes

Document History

DateAuthorChange
2026-05-26David HolmesInitial draft