Documentation

Complete guide to installing, configuring, and using FlexibleDatePicker in Angular applications.

Introduction

FlexibleDatePicker is an Angular 20+ date and time picker library built around headless selection engines and composable UI components. It uses date-fns for formatting and calendar math, ships with light/dark theming via CSS variables, and implements the Control Value Accessor (CVA) pattern for seamless reactive forms and template-driven forms integration.

Source code and releases: GitHub repository · npm package

All public pickers use the fdp-* selector prefix:

SelectorPurpose
fdp-date-pickerSingle date selection
fdp-date-range-pickerDate range with presets
fdp-time-pickerSingle time (roller wheel)
fdp-time-range-pickerStart/end time range
fdp-month-pickerMonth selection
fdp-month-range-pickerMonth range
fdp-year-pickerYear selection
fdp-year-range-pickerYear range

Features

See the full Features page for an overview of every capability, picker component, and developer experience highlight.

  • Eight picker components covering date, time, month, and year — single and range modes
  • Headless engines for custom UI or testing without the DOM
  • Roller/wheel time selection with infinite loop scrolling (23 → 0 → 1)
  • Optional inline time on date and date-range pickers
  • Preset shortcut sidebar for date ranges (Last 7 days, This month, etc.)
  • Responsive dual-calendar layout for range selection
  • Min/max bounds, custom disabled dates, and weekend blocking
  • Calendar and clock icons, configurable placeholders and formats
  • Light/dark/auto themes, per-picker colorScheme, and brand colors via customColors
  • Locale support and RTL layout via FlexLocaleService
  • Popover overlay with focus trap, escape to close, and outside-click dismiss
  • OnPush change detection and signal-based Angular APIs

Installation

Install from npm and its peer dependency:

Installation
terminal
npm install @manidev/ngx-flexible-date-picker date-fns

Import styles in your global stylesheet (required):

Implementation Code
styles.css
@import '@manidev/ngx-flexible-date-picker/themes/flexible-date-picker.css';

Quick start

Import a picker as a standalone component and bind it to a form control:

Implementation Code
demo.component.ts
import { Component } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { FlexDatePickerComponent } from '@manidev/ngx-flexible-date-picker';

@Component({
  selector: 'app-demo',
  imports: [ReactiveFormsModule, FlexDatePickerComponent],
  template: `
    <fdp-date-picker
      [formControl]="dateControl"
      placeholder="Select date"
      dateFormat="MMM d, yyyy"
      [showIcon]="true"
    />
  `,
})
export class DemoComponent {
  dateControl = new FormControl<Date | null>(null);
}

Template-driven forms work the same way with [(ngModel)].

Styling & theming

The library uses CSS custom properties defined in flexible-date-picker-base.css. You can theme globally with FlexThemeService, per picker with colorScheme, or with partial brand overrides via customColors. Try the live examples — the last card demonstrates all three approaches.

Global theme

Apply light, dark, or system-aware mode on <html>:

Implementation Code
theme.service.ts
import { FlexThemeService } from '@manidev/ngx-flexible-date-picker';

constructor(private theme: FlexThemeService) {}

enableDarkMode() {
  this.theme.setDarkMode(true);
}

useSystemTheme() {
  this.theme.setColorScheme('auto');
}

setColorScheme('auto') follows prefers-color-scheme. applyCustomColors() sets inline overrides on the document root; clearCustomColors() removes them.

Implementation Code
theme-global-custom.ts
this.theme.setColorScheme('light');
this.theme.applyCustomColors({
  primary: '#7c3aed',
  surface: '#faf5ff',
});
// this.theme.clearCustomColors();

Per-picker colorScheme

Every fdp-* picker accepts an optional colorScheme input: 'light', 'dark', or 'auto'. When set, the picker root gets data-flex-theme so it can differ from the page (e.g. a dark picker on a light page). Omit the input to inherit the document palette.

Implementation Code
app.component.html
<fdp-date-picker colorScheme="dark" placeholder="Select date" />

Custom colors (customColors)

Pass a partial FlexThemeTokens object to override specific CSS variables on that picker only. Combine with colorScheme for a built-in base plus brand accents — custom values win for the properties you set.

Implementation Code
app.component.html
<fdp-date-picker
  placeholder="Select date"
  [customColors]="{
    primary: '#be123c',
    primaryForeground: '#ffffff',
    range: '#fecdd3',
    radius: '0.5rem'
  }"
/>
Implementation Code
flex-theme-tokens.ts
interface FlexThemeTokens {
  surface?: string;
  surfaceElevated?: string;
  border?: string;
  primary?: string;
  primaryForeground?: string;
  muted?: string;
  mutedForeground?: string;
  accent?: string;
  accentForeground?: string;
  range?: string;
  today?: string;
  disabled?: string;
  radius?: string;
  shadow?: string;
}

CSS variables

Token fieldCSS variableDescription
surface--flex-surfaceBackground for popover panels, inputs, and elevated surfaces.
surfaceElevated--flex-surface-elevatedSecondary surface (e.g. nested panels).
primary--flex-primarySelected days, primary buttons, focus rings, active states.
primaryForeground--flex-primary-foregroundText/icon on primary backgrounds.
border--flex-borderBorders and dividers.
muted--flex-mutedHover and subtle fill backgrounds.
mutedForeground--flex-muted-foregroundSecondary text, weekday headers, inactive drum values.
accent--flex-accentAccent surface (presets, highlights).
accentForeground--flex-accent-foregroundText on accent surfaces.
range--flex-rangeIn-range highlight between start and end in range pickers.
today--flex-todayToday indicator background.
disabled--flex-disabledDisabled day/cell text color.
radius--flex-radiusBase border radius for panels, buttons, and inputs.
shadow--flex-shadowPopover box shadow.

Override any variable in your own CSS as well. The .dark class or data-flex-theme="dark" on <html> activates the dark palette globally.

Components overview

Every picker implements ControlValueAccessor and supports disabled via input or form control state. Outputs emit when the committed value changes (on selection or OK for time pickers).

All pickers share optional colorScheme ('light' | 'dark' | 'auto') and customColors (FlexThemeTokens) inputs for per-instance theming — see Styling & theming.

Date picker

Selector:fdp-date-picker

Value type:Date | null

InputTypeDefaultDescription
placeholderstring'Select date'Trigger label when no date is selected. Any string; shown in the closed input.
dateFormatstring'MMM d, yyyy' date-fns format token for the trigger display. Examples: 'yyyy-MM-dd', 'PP', 'EEEE, MMM d'. See the date-fns format docs.
minDate | nullnullEarliest selectable calendar day (inclusive). Days before this are disabled. Use null for no lower bound.
maxDate | nullnullLatest selectable calendar day (inclusive). Days after this are disabled. Use null for no upper bound.
isDateDisabled(date: Date) => boolean Optional callback to disable individual dates. Return true to block a day (e.g. weekends: date.getDay() === 0 || date.getDay() === 6). Runs in addition to min/max.
timeFlexTimeConfig{} Inline time drum config. Set enabled: true to show hour/minute rollers after picking a date. Supports format, hourStep, minuteStep, use24Hour, showSeconds, and defaultTime.
disabledbooleanfalseWhen true, the trigger button is non-interactive. Also respects reactive form disabled state.
showIconbooleantrueShow (true) or hide (false) the calendar icon on the trigger.
colorScheme'light' | 'dark' | 'auto' Per-picker light/dark/system theme. Sets data-flex-theme on the picker root. Omit to inherit the document theme from <html>.
customColorsFlexThemeTokens Partial palette overrides applied as --flex-* CSS variables on this picker. Combine with colorScheme to start from a preset and override brand colors (e.g. primary, range).

Output:dateChange — emits Date | null

When time.enabled is true, the popover stays open after date selection so the user can adjust time. The popover closes on outside click or Escape.

Implementation Code
app.component.html
<fdp-date-picker
  [formControl]="date"
  dateFormat="MMM d, yyyy"
  [time]="{ enabled: true, format: 'HH:mm', showSeconds: false }"
/>

Date range picker

Selector:fdp-date-range-picker

Value type:{ start: Date | null; end: Date | null }

InputTypeDefaultDescription
placeholderstring'Select date range'Trigger label when start or end is unset. Any string.
dateFormatstring'MMM d, yyyy' date-fns format for both range endpoints in the trigger. Examples: 'MMM d, yyyy', 'yyyy-MM-dd', 'PP'.
min / maxDate | nullnull Inclusive bounds applied to both start and end selection. null means no bound. Individual days outside the range are not selectable.
isDateDisabled(date: Date) => boolean Optional per-day disable callback. Return true to block a date from either end of the range. Combined with min/max constraints.
presetSidebarFlexPresetSidebarConfig{} Shortcut sidebar config. enabled: true (default) or false. presets: custom PresetRange[], omit for built-ins (Today, Yesterday, Last 7 Days, Last 30 Days, This Month, Previous Month, This Year), or pass [] to hide all presets.
calendarLayoutFlexDateRangeCalendarConfig{ mode: 'auto' } Number of month panels. mode values: 'auto' — two months on desktop, one on mobile (default); 'single' — always one month; 'double' — always two consecutive months.
timeFlexTimeConfig{} Optional start/end time drums shown below the calendars when enabled: true. Same options as single date picker time config; applied separately to range start and end.
disabledbooleanfalseDisables the trigger and popover when true. Honors form control disabled state.
showIconbooleantrueShow (true) or hide (false) the calendar icon on the trigger.

Output:rangeChange

Includes Apply/Cancel action bar. Range is committed on Apply.

Time pickers

Time picker — fdp-time-picker

Value type:Date | null (time stored on a reference date)

InputTypeDefaultDescription
placeholderstring'Select time'Trigger label when no time is set. Any string.
timeFormatstring'HH:mm' date-fns format for the trigger. Common values: 'HH:mm' (24h), 'h:mm a' (12h with AM/PM), 'HH:mm:ss' when seconds are enabled.
hourStepnumber1Increment between hour options in the roller. Positive integer (e.g. 1, 2, 6).
minuteStepnumber1Increment between minute options. Common values: 1, 5, 15, 30.
secondStepnumber1Increment for the seconds column when showSeconds is true.
use24Hourbooleantruetrue — 0–23 hour drum (default). false — 1–12 hour drum plus AM/PM column.
showSecondsbooleanfalsetrue adds a third roller column for seconds. false (default) shows hours and minutes only.
disabledbooleanfalseDisables the trigger when true. Respects form control disabled state.
showIconbooleantrueShow (true) or hide (false) the clock icon on the trigger.

Output:timeChange

Time range picker — fdp-time-range-picker

Value type:TimeRange{ start: Date | null; end: Date | null }

Accepts the same inputs as fdp-time-picker (defaults shown above), plus placeholder defaulting to 'Select time range'. Start and end rollers appear side by side; OK commits the range, Cancel reverts.

Output:rangeChange

Roller wheel behavior

  • Three visible rows: previous value, selected value, next value
  • Infinite loop — hour 1 shows 23 above and 2 below
  • Scroll or tap to change; OK commits, Cancel reverts draft

Month pickers

Month picker — fdp-month-picker

Value type:Date | null (normalized to first of month)

InputTypeDefaultDescription
placeholderstring'Select month'Trigger label when no month is selected.
monthFormatstring'MMM yyyy' date-fns format for the selected month. Examples: 'MMM yyyy', 'MMMM yyyy', 'MM/yyyy'.
min / maxDate | nullnull Inclusive month bounds (normalized to month start). Months outside the range are disabled. null for no bound.
disabledbooleanfalseDisables the trigger when true.
showIconbooleantrueShow (true) or hide (false) the calendar icon.

Output:monthChange

Month range picker — fdp-month-range-picker

Value type:DateRange — months normalized to the first day of each selected month.

InputTypeDefaultDescription
placeholderstring'Select month range'Trigger label when the range is incomplete.
monthFormatstring'MMM yyyy'date-fns format for both range endpoints in the trigger.
min / maxDate | nullnullInclusive month bounds for start and end selection. null for no bound.
disabledbooleanfalseDisables the trigger when true.
showIconbooleantrueShow (true) or hide (false) the calendar icon.

Output:rangeChange

Year pickers

Year picker — fdp-year-picker

Value type:Date | null (normalized to January 1 of the selected year)

InputTypeDefaultDescription
placeholderstring'Select year'Trigger label when no year is selected.
yearFormatstring'yyyy'date-fns format for the trigger. Typically 'yyyy'; also supports 'yy'.
min / maxDate | nullnullInclusive year bounds (normalized to Jan 1). Years outside the range are disabled.
disabledbooleanfalseDisables the trigger when true.
showIconbooleantrueShow (true) or hide (false) the calendar icon.

Output:yearChange

Year range picker — fdp-year-range-picker

Value type:DateRange — years normalized to January 1.

InputTypeDefaultDescription
placeholderstring'Select year range'Trigger label when the range is incomplete.
yearFormatstring'yyyy'date-fns format for both endpoints in the trigger.
min / maxDate | nullnullInclusive year bounds for start and end. null for no bound.
disabledbooleanfalseDisables the trigger when true.
showIconbooleantrueShow (true) or hide (false) the calendar icon.

Output:rangeChange

Shared configuration

FlexTimeConfig

Used by fdp-date-picker and fdp-date-range-picker via the time input:

Implementation Code
flex-time-config.ts
interface FlexTimeConfig {
  enabled?: boolean;       // default false
  format?: string;         // default 'HH:mm'
  minuteStep?: number;     // default 1
  hourStep?: number;       // default 1
  defaultTime?: { hours: number; minutes: number; seconds?: number };
  use24Hour?: boolean;     // default true
  showSeconds?: boolean;   // default false
}

FlexPresetSidebarConfig

Implementation Code
flex-preset-sidebar-config.ts
interface FlexPresetSidebarConfig {
  enabled?: boolean;         // default true
  presets?: PresetRange[];   // built-in defaults when omitted
}

interface PresetRange {
  id: string;
  label: string;
  getRange: (referenceDate?: Date) => DateRange;
}

FlexDateRangeCalendarConfig

Implementation Code
flex-date-range-calendar-config.ts
interface FlexDateRangeCalendarConfig {
  mode?: 'single' | 'double' | 'auto';  // default 'auto'
}
  • auto — two months on desktop, one on mobile
  • single — always one calendar
  • double — always two consecutive months

FlexThemeTokens & FlexColorScheme

FlexColorScheme is 'light' | 'dark' | 'auto'. Use it on any picker’s colorScheme input or with FlexThemeService.setColorScheme(). FlexThemeTokens is a partial map of palette fields to CSS color/length values for the customColors input and applyCustomColors().

Implementation Code
flex-theme-tokens.ts
interface FlexThemeTokens {
  surface?: string;
  surfaceElevated?: string;
  border?: string;
  primary?: string;
  primaryForeground?: string;
  muted?: string;
  mutedForeground?: string;
  accent?: string;
  accentForeground?: string;
  range?: string;
  today?: string;
  disabled?: string;
  radius?: string;
  shadow?: string;
}

The same colorScheme and customColors inputs are available on every fdp-* picker component.

Forms integration

All pickers register as NG_VALUE_ACCESSOR providers.

Reactive forms

Implementation Code
range-form.component.ts
readonly range = new FormControl<DateRange>({
  start: null,
  end: null,
});

<fdp-date-range-picker [formControl]="range" />

Template-driven

Implementation Code
app.component.html
<fdp-date-picker [(ngModel)]="selectedDate" name="date" />

Validation

Use standard Angular validators on the form control. The date picker reactive example in the playground uses Validators.required.

Locale & RTL

Implementation Code
locale.service.ts
import { FlexLocaleService } from '@manidev/ngx-flexible-date-picker';

constructor(private locale: FlexLocaleService) {}

setFrench() {
  this.locale.setLocale('fr');
}

setArabic() {
  this.locale.setLocale('ar');
  document.documentElement.dir = 'rtl';
}

Weekday labels and calendar layout respect the configured locale. Set dir="rtl" on <html> for right-to-left trigger alignment.

Headless engines

Build custom UIs or unit-test selection logic without rendering components. Engines live under @manidev/ngx-flexible-date-picker public API:

  • createDatePickerEngine()
  • createDateRangePickerEngine()
  • createTimePickerEngine()
  • createTimeRangePickerEngine()
  • createMonthPickerEngine()
  • createMonthRangePickerEngine()
  • createYearPickerEngine()
  • createYearRangePickerEngine()

Each engine exposes state, actions, and selectors for calendar grids, validation, and open/close lifecycle.

Implementation Code
date-picker.engine.ts
import { createDatePickerEngine } from '@manidev/ngx-flexible-date-picker';

const engine = createDatePickerEngine({ weekStartsOn: 1 });
engine.actions.open();
engine.actions.selectDate(new Date(2026, 4, 13));
console.log(engine.state.value);

Services

ServicePurpose
FlexThemeService Global theming on <html>: setColorScheme('light' | 'dark' | 'auto'), setDarkMode(), toggleDarkMode(), getColorScheme(), isDarkMode(), applyCustomColors(tokens), and clearCustomColors().
FlexLocaleService Set active locale with setLocale(code). Supported codes include 'en', 'fr', 'de', 'ar'. Controls weekday labels and week start day via weekStartsOn() (0 = Sunday, 1 = Monday).
FlexOverlayService Manages popover placement (above/below anchor), focus trap, outside-click dismiss, and mobile bottom-sheet layout. Used internally by picker components.
PickerEngineBridgeService Signal bridge syncing headless engine state with component UI. Useful when building custom picker shells on top of the engines.

Accessibility

  • Trigger buttons expose aria-expanded and aria-haspopup="dialog"
  • Popover panels use role="dialog" with accessible names
  • Calendar grids use semantic day buttons; time drums use role="listbox"
  • Keyboard: Escape closes popover; Tab is trapped inside open dialogs
  • Focus returns to logical targets on dismiss

API reference

Full public exports from @manidev/ngx-flexible-date-picker:

Components

Implementation Code
public-api.ts
FlexDatePickerComponent
FlexDateRangePickerComponent
FlexTimePickerComponent
FlexTimeRangePickerComponent
FlexMonthPickerComponent
FlexMonthRangePickerComponent
FlexYearPickerComponent
FlexYearRangePickerComponent

Types & models

Implementation Code
models.ts
DateRange, TimeRange, FlexTimeConfig
FlexPresetSidebarConfig, FlexDateRangeCalendarConfig
FlexColorScheme, FlexThemeTokens
PresetRange, CalendarMonth, CalendarDay
Granularity, WeekStart, LocaleCode

Utilities

Implementation Code
utils.ts
normalizeDate, mergeDateAndTime, getTimeParts
generateHourOptions, generateMinuteOptions
getWeekdayLabels, buildLoopedOptions