ngxsmk-datepicker

July 29, 2026 · View on GitHub

ngxsmk-datepicker - Lightweight Angular Date Range Picker

ngxsmk-datepicker – Modern Angular Date Picker & Range Picker

The Gold Standard for Premium Angular Calendar Selection

npm version CI Angular License Buy me a coffee Bundle Size Zoneless

npm i ngxsmk-datepicker

Live demoStackBlitz (repo)API docsIssuesBuy me a coffee

StackBlitz: after it boots, run npm install then npm start in the terminal to serve the demo app (demo-app).


Last updated: July 29, 2026 - Current stable: v3.0.3

Overview

ngxsmk-datepicker is a high-performance, enterprise-ready date and range picker engineered for the modern Angular ecosystem (v17+). Built from the ground up with Angular Signals, it delivers a seamless, zoneless-ready experience for both desktop and mobile (Ionic) applications.

Stable Release: v3.0.3 is the current stable release with compiled fesm2022 output and type declarations.

Stable line: v2.3.x includes side-by-side calendars, natural language input, searchable timezone selection dropdown UI, dynamic range presets, and warning range highlighting. Versions 2.0.10 and 2.0.11 were broken and have been unpublished; use v2.1.1+ or current v3.0.3 on npm.


📌 Table of Contents

  1. 📷 Screenshots
  2. ✨ Features
  3. 🤔 Why this library?
  4. 🌐 Discoverability
  5. 📋 Compatibility
  6. 🌍 Localization (i18n)
  7. 📦 Installation
  8. 🚀 Quick start / usage
  9. 🔌 Framework Integration
  10. ⚙️ API Reference
  11. 🎨 Theming
  12. ⌨️ Keyboard Navigation

📷 Screenshots

Angular Standalone DatePicker Single Selection Mode Angular Date Range Picker Selection Mode Mobile Angular DatePicker Ionic Compatibility

✨ Features

Core Capabilities

  • 💎 Signal-Driven Engine: Hyper-reactive state management using Angular Signals.
  • 🌓 Native Dark Mode: Beautifully crafted themes for light and dark environments.
  • 📱 Mobile-First UX: Native mobile picker integration with touch gestures and haptic feedback.
  • 🧩 Minimal footprint: Standalone component; Luxon is the only date peer beyond Angular (no full UI suite required).
  • Performance++: Lazy-loaded calendar months, memoized calculations, and tree-shakable architecture.

Advanced Functionality

  • 📅 Google Calendar Sync: Built-in support for seamlessly syncing and displaying events natively from Google Calendar.
  • 🗓️ Adjacent Month Days (showOtherMonths): Display trailing and leading days from adjacent months in the calendar grid.
  • 📐 Responsive Control ([responsive]): Disable viewport max-width responsive overrides for fixed-width container embedding (#299).
  • 🌐 8-Language i18n: Full localization for en, de, es, sv, ko, zh, ja, and fr.
  • 🔢 ISO Week Numbers: Optional week-number column via [showWeekNumbers].
  • ⌨️ Guided Input Masking: [inputMask] auto-inserts separators as users type (e.g. 1212/).
  • 🌍 Secondary Calendars: Annotate day cells with Hijri, Jalali, Hebrew, Buddhist, or Japanese dates via [secondaryCalendar].
  • 🏨 Availability Calendars: Per-day prices, indicator dots, and classes via [dayMetadata]; server-driven blocked dates via [asyncDateFilter].
  • 🎛️ Custom Action Bars: [calendarHeaderTemplate] / [calendarFooterTemplate] slots with clear()/close() actions.
  • 🛠️ Plugin Architecture: Extend functionality via hooks for rendering, validation, and shortcuts.
  • 🧪 Signal Forms Native: Direct integration with Angular 21's new Signal Forms API.
  • 🚀 Zoneless Ready: Optimized for the future of Angular—works perfectly without zone.js.
  • Full Accessibility: WAI-ARIA compliant with extensive keyboard navigation support.

Why this library?

Use ngxsmk-datepicker when you want an enterprise-grade date / range picker with strong mobile, i18n, timezone, Ionic, and SSR support on Angular 17–22+, without adopting a heavy Material UI stack or legacy Day.js dependencies.

Feature Comparison Matrix

Feature / Capabilityngxsmk-datepickerAngular Material datepickervlio20/angular-datepicker
Angular 17–22+ Signals Engine⚡ Native Signals (0% Zone.js)⚠️ RxJS / Legacy ChangeDetector❌ Legacy Angular 15-18
Standalone Component & Zero CDK✅ Yes (Lightweight ~127KB)❌ Requires @angular/material + @angular/cdk⚠️ Requires legacy CDK
Mobile & Touch (Ionic 7/8+)📱 Built-in Touch & Safe Area Insets⚠️ Mobile UI requires custom CSS❌ Poor Mobile / iOS support
Date-Time Preservation (#30181)✅ Preserves hours/minutes on click❌ Resets time on date click❌ No native time preservation
Adjacent Month Days (showOtherMonths)✅ Built-in input⚠️ Not supported natively⚠️ Partial support
Fixed Container Control ([responsive])✅ Built-in input (#299)❌ Not supported❌ Not supported
Signal Forms Native ([field])✅ Built-in (Angular 21+)❌ Not supported❌ Not supported
Google Calendar Sync & Multi-Calendars✅ Built-in❌ Requires custom code❌ Not supported
SSR / Hydration Safety✅ 100% Guarded (DOCUMENT)⚠️ Requires CDK SSR overlays❌ Window access errors

This is not a heavy UI framework; it is a standalone datepicker engineered for maximum performance, accessibility, and theming flexibility. See the live demo and COMPATIBILITY for details.

🌐 Discoverability

Maintainers (GitHub): consider repository Topics such as: angular, datepicker, date-range-picker, luxon, standalone-components, i18n, angular-universal, ionic, accessibility.

Community: if this project helped you, stars and accurate comparisons in blog posts or issue threads help others find it. Curated lists (for example awesome-angular-style repos) usually accept small PRs that add a one-line link and follow their contribution rules—check each list’s guidelines before opening a PR.

Security: report sensitive issues per SECURITY.md, not via public issues.

📋 Compatibility

For detailed compatibility information, see COMPATIBILITY.md.

Quick Reference

Angular VersionStatusCore FeaturesSignal FormsSSRZoneless
Angular 17✅ Fully Supported✅ All
Angular 18✅ Fully Supported✅ All
Angular 19✅ Fully Supported✅ All
Angular 20✅ Fully Supported✅ All
Angular 21✅ Fully Supported✅ All
Angular 22+🔄 Future Support✅ All

Zone.js: Optional - The library works with or without Zone.js (zoneless apps supported)

SSR: ✅ Fully compatible with Angular Universal and server-side rendering

Peer Dependencies: @angular/core >=17.0.0 <24.0.0

🔒 API Stability & Deprecation Policy

API Stability Guarantees

  • Public API: All public APIs (inputs, outputs, methods) are stable within a major version
  • Experimental Features: Features marked as experimental may change in minor versions
  • Internal APIs: Private methods and internal services are not part of the public API and may change without notice

Deprecation Policy

  • Deprecation Period: Features are deprecated for at least 2 major versions before removal
  • Deprecation Warnings:
    • @deprecated JSDoc tags in code
    • Console warnings in development mode
    • Clear documentation in CHANGELOG.md
  • Migration Guides: Provided in MIGRATION.md for all breaking changes
  • Breaking Changes: Only occur in major version releases (semver)

Stable APIs

The following are considered stable public APIs:

  • Component inputs and outputs (@Input(), @Output())
  • Public methods documented in API docs
  • Exported types and interfaces
  • Service APIs (when marked as public)

Experimental Features

Features marked as experimental may change:

  • Signal Forms support ([field] input) - Experimental in v1.9.x, stable in v2.0.0+
  • Some advanced selection modes
  • Plugin architecture hooks (subject to refinement)

For details, see CONTRIBUTING.md.

📦 Installation

ng add ngxsmk-datepicker

The ng add schematic installs the package, adds the luxon peer dependency if it is missing, and prints a getting-started snippet. Plain npm works too:

npm install ngxsmk-datepicker@3.0.3

Alternative installation

You can install without npm using any of these methods (peer dependencies must still be installed in your app):

MethodCommand
Yarnyarn add ngxsmk-datepicker@3.0.3
pnpmpnpm add ngxsmk-datepicker@3.0.3
Bunbun add ngxsmk-datepicker@3.0.3
From Gitnpm install github:NGXSMK/ngxsmk-datepicker#v3.0.3 (requires the repo to have built output or you build from source)
Local pathBuild the library in the repo (npx ng build ngxsmk-datepicker), then npm install /path/to/ngxsmk-datepicker/dist/ngxsmk-datepicker
CDN (ESM)Use unpkg or jsDelivr in your bundler or import map; peer dependencies (Angular, etc.) must be installed in your app.

For all options and caveats, see docs/INSTALLATION.md.

Usage

ngxsmk-datepicker is a standalone component, so you can import it directly into your component or module.

Signal Forms (Angular 21)

You can bind directly to a writable Signal using standard two-way binding. This works seamlessly alongside traditional Reactive Forms.

import { signal } from "@angular/core";
import { DatepickerValue } from "ngxsmk-datepicker";

export class MyComponent {
  dateSig = signal<DatepickerValue>(null);
}
<ngxsmk-datepicker mode="single" [value]="dateSig()" (valueChange)="dateSig.set($event)"> </ngxsmk-datepicker>

<p>Signal value: {{ dateSig() | json }}</p>

This pattern is also compatible with computed/linked signals produced by httpResource, enabling powerful data flows with Angular 21.

Signal Forms with [field] Input (Angular 21+)

For direct integration with Angular Signal Forms, use the [field] input. The datepicker automatically tracks dirty state when using this binding:

import { Component, signal, form, objectSchema } from "@angular/core";
import { NgxsmkDatepickerComponent } from "ngxsmk-datepicker";

@Component({
  selector: "app-form",
  standalone: true,
  imports: [NgxsmkDatepickerComponent],
  template: `
    <form>
      <ngxsmk-datepicker [field]="myForm.dateInQuestion" mode="single" placeholder="Select a date"> </ngxsmk-datepicker>
    </form>
  `,
})
export class FormComponent {
  localObject = signal({ dateInQuestion: new Date() });

  myForm = form(
    this.localObject,
    objectSchema({
      dateInQuestion: objectSchema<Date>(),
    }),
  );
}

The [field] input provides automatic two-way binding with signal forms - no manual event handling needed! It also automatically tracks the form's dirty state, so form().dirty() will return true after a user selects a date.

For detailed Signal Forms integration including dirty state tracking, see the Signal Forms Integration Guide.

Documentation

1. Import the Component

All public exports (component, utilities, types, services) come from the main package entry: 'ngxsmk-datepicker' (there is no separate /utils subpath). In your component file (e.g., app.component.ts), import the component (or the module—see troubleshooting below).

import { Component } from '@angular/core';
import { NgxsmkDatepickerComponent, DateRange, HolidayProvider } from 'ngxsmk-datepicker';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [NgxsmkDatepickerComponent],
  templateUrl: './app.component.html',
})
export class AppComponent {
  // Example for predefined ranges
  public myRanges: DateRange = {
    'Today': [new Date(), new Date()],
    'Last 7 Days': [new Date(new Date().setDate(new Date().getDate() - 6)), new Date()],
    'This Month': [new Date(new Date().getFullYear(), new Date().getMonth(), 1), new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0)],
  };

  // Example for disabling weekends
  isWeekend = (date: Date): boolean => {
    const day = date.getDay();
    return day === 0 || day === 6; // Sunday or Saturday
  };

  onDateChange(value: Date | { start: Date; end: Date } | Date[]) {
    console.log('Date changed:', value);
  }
}

If you see NG1010 ('imports' must be an array... Value could not be determined statically) when using the Angular compiler plugin or in strict AOT builds, use the wrapper module instead: import { NgxsmkDatepickerModule } from 'ngxsmk-datepicker' and set imports: [NgxsmkDatepickerModule]. The template stays the same (<ngxsmk-datepicker>).

2. Add it to Your Template

Use the <ngxsmk-datepicker> selector in your HTML template.

<h2>Advanced Date Range Picker</h2>

<ngxsmk-datepicker [mode]="'range'" [ranges]="myRanges" [showTime]="true" [minuteInterval]="15" [minDate]="today" [isInvalidDate]="isWeekend" [locale]="'en-US'" [theme]="'light'" [inline]="'auto'" (valueChange)="onDateChange($event)"></ngxsmk-datepicker>

#### **3. Disabled Dates Example** Disable specific dates by passing an array of date strings or Date objects: ```typescript // In your component disabledDates = ['10/21/2025', '08/21/2025', '10/15/2025', '10/8/2025', '10/3/2025']; // In your template
<ngxsmk-datepicker [mode]="'single'" [disabledDates]="disabledDates" placeholder="Select a date"> </ngxsmk-datepicker>

4. Holiday Tooltips Example

Holiday dates automatically show tooltips when you hover over them:

// Holiday provider with tooltips
class MyHolidayProvider implements HolidayProvider {
  private holidays: { [key: string]: string } = {
    '2025-01-01': 'New Year\'s Day',
    '2025-07-04': 'Independence Day',
    '2025-12-25': 'Christmas Day',
  };

  isHoliday(date: Date): boolean {
    const key = this.formatDateKey(date);
    return !!this.holidays[key];
  }

  getHolidayLabel(date: Date): string | null {
    const key = this.formatDateKey(date);
    return this.holidays[key] || null;
  }
}

// In your template
<ngxsmk-datepicker
  [holidayProvider]="holidayProvider"
  [disableHolidays]="false"
  placeholder="Hover over holidays to see tooltips">
</ngxsmk-datepicker>

🔌 Framework Integration

Angular Material Form Fields

Integrate with Angular Material's form field components for a seamless Material Design experience. Works with both standalone and non-standalone components:

Standalone Components:

import { Component } from "@angular/core";
import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatInputModule } from "@angular/material/input";
import { NgxsmkDatepickerComponent } from "ngxsmk-datepicker";

@Component({
  selector: "app-material-form",
  standalone: true,
  imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule, NgxsmkDatepickerComponent],
  template: `
    <form [formGroup]="myForm">
      <mat-form-field appearance="outline">
        <mat-label>Select Date</mat-label>
        <ngxsmk-datepicker mode="single" formControlName="date" placeholder="Choose a date"> </ngxsmk-datepicker>
      </mat-form-field>
    </form>
  `,
})
export class MaterialFormComponent {
  myForm = new FormGroup({
    date: new FormControl<Date | null>(null),
  });
}

Non-Standalone (NgModules): Add the directive file from INTEGRATION.md § Angular Material, then add it to your module imports (with NgxsmkDatepickerComponent, MatFormFieldModule, etc.) and use ngxsmkMatFormFieldControl on the datepicker in templates.

With Date Range:

<mat-form-field appearance="fill">
  <mat-label>Date Range</mat-label>
  <ngxsmk-datepicker mode="range" [showTime]="true" formControlName="dateRange"> </ngxsmk-datepicker>
</mat-form-field>

Ionic Components

For best integration with Ionic, import the integration styles in your global CSS/SCSS file:

@import "ngxsmk-datepicker/styles/ionic-integration.css";

Automatic Theming: The datepicker automatically detects and uses Ionic CSS variables (e.g., --ion-color-primary, --ion-background-color) so it matches your app's theme out of the box without extra configuration.

Works seamlessly with Ionic form components and follows Ionic design patterns:

import { Component } from "@angular/core";
import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms";
import { IonItem, IonLabel, IonInput } from "@ionic/angular/standalone";
import { NgxsmkDatepickerComponent } from "ngxsmk-datepicker";

@Component({
  selector: "app-ionic-form",
  standalone: true,
  imports: [ReactiveFormsModule, IonItem, IonLabel, IonInput, NgxsmkDatepickerComponent],
  template: `
    <form [formGroup]="myForm">
      <ion-item>
        <ion-label position="stacked">Appointment Date</ion-label>
        <ngxsmk-datepicker mode="single" formControlName="appointmentDate" placeholder="Select date"> </ngxsmk-datepicker>
      </ion-item>
    </form>
  `,
})
export class IonicFormComponent {
  myForm = new FormGroup({
    appointmentDate: new FormControl<Date | null>(null),
  });
}

With Ionic Datetime Styling:

<ion-item>
  <ion-label>Check-in / Check-out</ion-label>
  <ngxsmk-datepicker mode="range" [theme]="'light'" formControlName="bookingDates"> </ngxsmk-datepicker>
</ion-item>

React, Vue, & Vanilla JS (Web Components)

Because ngxsmk-datepicker is highly decoupled from heavy external dependencies, it can be exported as a standard Custom Web Component using Angular Elements. This allows you to use exactly the same datepicker in React, Vue, Svelte, or Vanilla JavaScript projects seamlessly!

1. Create a Custom Element Wrapper

import { createApplication } from '@angular/platform-browser';
import { createCustomElement } from '@angular/elements';
import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';

(async () => {
  const app = await createApplication();
  const DatepickerElement = createCustomElement(NgxsmkDatepickerComponent, { injector: app.injector });
  customElements.define('ngxsmk-datepicker', DatepickerElement);
})().catch(console.error);

2. Use It Natively Anywhere

<!-- In any HTML, React, Vue, or Svelte file -->
<ngxsmk-datepicker id="myPicker" mode="range" theme="light"></ngxsmk-datepicker>

<script>
  // Add native DOM event listeners
  document.getElementById('myPicker').addEventListener('dateSelect', (e) => {
    console.log('Selected date:', e.detail);
  });
</script>

For full working examples (including React & Vue bindings), check out the /examples directory in our GitHub repository!

Plain HTML Inputs

Use with standard HTML form inputs for maximum flexibility:

import { Component } from "@angular/core";
import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms";
import { NgxsmkDatepickerComponent } from "ngxsmk-datepicker";

@Component({
  selector: "app-plain-form",
  standalone: true,
  imports: [ReactiveFormsModule, NgxsmkDatepickerComponent],
  template: `
    <form [formGroup]="myForm">
      <label for="birthdate">Birth Date</label>
      <ngxsmk-datepicker id="birthdate" mode="single" formControlName="birthdate" placeholder="MM/DD/YYYY"> </ngxsmk-datepicker>

      <button type="submit">Submit</button>
    </form>
  `,
})
export class PlainFormComponent {
  myForm = new FormGroup({
    birthdate: new FormControl<Date | null>(null),
  });
}

With Native HTML5 Validation:

<form [formGroup]="myForm">
  <div class="form-group">
    <label for="event-date">Event Date *</label>
    <ngxsmk-datepicker id="event-date" mode="single" formControlName="eventDate" [minDate]="today" required> </ngxsmk-datepicker>
  </div>
</form>

Form Validation

By default, the datepicker input is readonly to prevent invalid date strings and force selection via the calendar. However, browsers do not validate readonly fields during native form submission.

Behavior:

  • Native browser validation (e.g., blocking submit on required fields) will NOT trigger on the datepicker by default.
  • Custom validation (e.g., Angular validators) works normally but often only shows errors after the control is "touched".

Solutions:

  1. Enable Typing (Recommended for Native Validation): Set [allowTyping]="true" to make the input standard editable field. This enables native browser validation tooltips and submit-blocking.

    <ngxsmk-datepicker [allowTyping]="true" required ...></ngxsmk-datepicker>
    
  2. Custom Validation Logic: If you prefer the readonly behavior, ensure your form submission handler explicitly checks form.invalid before proceeding, as the browser won't stop the submit button click.

⚙️ API Reference

Inputs

PropertyTypeDefaultDescription
mode'single' | 'range' | 'multiple''single'The selection mode.
inlineboolean | 'always' | 'auto'falseControls the display mode. true or 'always' for inline, 'auto' for responsive.
localestringnavigator.languageSets the locale for language and regional formatting (e.g., 'en-US', 'de-DE').
theme'light' | 'dark''light'The color theme.
showRangesbooleantrueIf true, displays the predefined ranges panel when in 'range' mode.
minDateDateInputnullThe earliest selectable date.
maxDateDateInputnullThe latest selectable date.
isInvalidDate(date: Date) => boolean() => falseA function to programmatically disable specific dates.
rangesDateRangenullAn object of predefined date ranges.
minuteIntervalnumber1Interval for minute dropdown options.
showTimebooleanfalseEnables the hour/minute/AM/PM selection section.
timeOnlybooleanfalseDisplay time picker only (no calendar). Automatically enables showTime.
use24HourbooleanfalseEnable 24-hour time format (00-23) and hide AM/PM selector.
allowTypingbooleanfalseEnable manual typing in the input field. Required for native validation.
displayFormatstringnullCustom date format string (e.g., 'MM/DD/YYYY').
showCalendarButtonbooleanfalseShow/hide the calendar icon button.
valueDatepickerValuenullProgrammatic value setting from code.
startAtDateInputnullThe date to initially center the calendar view on.
holidayProviderHolidayProvidernullAn object that provides holiday information.
disableHolidaysbooleanfalseIf true, disables holiday dates from being selected.
disabledDates(string | Date)[][]Array of dates to disable.
weekStartnumber | nullnullOverride week start day (0=Sunday, 1=Monday, etc.).
yearRangenumber10Number of years before/after current year to show in year dropdown.
clearLabelstring'Clear'Custom label for the clear button.
closeLabelstring'Close'Custom label for the close button.
prevMonthAriaLabelstring'Previous month'Aria label for previous month navigation button.
nextMonthAriaLabelstring'Next month'Aria label for next month navigation button.
clearAriaLabelstring'Clear selection'Aria label for clear button.
closeAriaLabelstring'Close calendar'Aria label for close button.
classesobjectundefinedTailwind-friendly class overrides (wrapper, input, popover, etc.).
enableGoogleCalendarbooleanfalseEnable seamless Google Calendar integration and sync.
googleClientIdstring | nullnullGoogle API OAuth 2.0 Web Client ID for authentication.
calendarsnumber1Multi-calendar display layout (supports 1, 2, or 3 side-by-side calendars).
rangePresetFactory(today: Date) => DatePreset[]nullCallback function supplying dynamic rolling range presets.
showTimezoneSelectorbooleanfalseEnables searchable IANA timezone selection dropdown UI.
enableNaturalLanguagebooleanfalseEnables manual relative keyboard typing input (e.g. "today", "in 3 days").
showWeekNumbersbooleanfalseShows an ISO 8601 week-number column on the left of the day grid.
weekNumberLabelstring'Wk'Header label for the week-number column (e.g. "KW", "S").
inputMaskboolean | stringfalseGuided input masking while typing: true uses displayFormat (or MM/DD/YYYY); a string (e.g. 'DD.MM.YYYY') sets an explicit pattern. Requires allowTyping.
asyncDateFilter(start: Date, end: Date) => Promise<DateInput[]>nullServer-driven disabled dates: called with the visible range on every navigation; resolved dates are disabled. Stale responses are discarded.
secondaryCalendar'islamic' | 'persian' | 'hebrew' | 'buddhist' | 'japanese'nullAnnotates each day cell with its date in a second calendar system (rendered via Intl; the grid stays Gregorian).
dayMetadata(date: Date) => DayMetadatanullPer-day decorations without templates: label under the day number (e.g. a price), indicator dot color, extra CSS classes, tooltip.
calendarHeaderTemplateTemplateRefnullCustom content at the top of the popover/inline calendar. Context: let-actions{ clear(), close() }.
calendarFooterTemplateTemplateRefnullReplaces the default Clear/Close footer with custom actions. Context: let-actions{ clear(), close() }.

Outputs

EventPayloadDescription
valueChangeDatepickerValueEmits the newly selected date, range, or array of dates.
action{ type: string; payload?: any }Emits various events like dateSelected, timeChanged, etc.
googleSyncClickvoidEmitted when the user clicks the Google Calendar sync button.
invalidRange{ start: Date; end: Date; disabledDatesInside: Date[] }Emitted when selected date range contains disabled dates.
naturalLanguageResolvedDate | { start: Date; end: Date }Emitted when user types relative natural language date input.
timezoneChangestringEmitted when timezone selection is changed.
asyncDateFilterLoadingbooleanEmits true while an asyncDateFilter request is in flight, false when it settles.
asyncDateFilterErrorunknownEmitted when asyncDateFilter rejects; the previous disabled set is kept.

🎨 Theming

CSS Variables

You can easily customize the colors of the datepicker by overriding the CSS custom properties in your own stylesheet.

ngxsmk-datepicker {
  --datepicker-primary-color: #d9267d;
  --datepicker-primary-contrast: #ffffff;
  --datepicker-range-background: #fce7f3;
}

Tailwind/ngClass Support

For Tailwind CSS or custom class-based theming, use the classes input:

<ngxsmk-datepicker
  mode="single"
  [classes]="{
    inputGroup: 'rounded-lg border',
    input: 'px-3 py-2 text-sm',
    popover: 'shadow-2xl',
    dayCell: 'hover:bg-indigo-50',
    footer: 'flex justify-end gap-2',
    clearBtn: 'btn btn-ghost',
    calendarBtn: 'btn btn-icon',
    closeBtn: 'btn btn-primary'
  }"
>
</ngxsmk-datepicker>

Dark Theme

To enable the dark theme, simply bind the theme input:

<ngxsmk-datepicker [theme]="'dark'"></ngxsmk-datepicker>

Calendar Button Visibility

Control the visibility of the calendar icon button:

<!-- Hide calendar button (default - users can still click input to open calendar) -->
<ngxsmk-datepicker mode="single"> </ngxsmk-datepicker>

<!-- Show calendar button -->
<ngxsmk-datepicker [showCalendarButton]="true" mode="single"> </ngxsmk-datepicker>

<!-- Useful with allowTyping for custom UI -->
<ngxsmk-datepicker [allowTyping]="true" [showCalendarButton]="false" mode="single"> </ngxsmk-datepicker>

🌍 Localization (i18n)

The locale input controls all internationalization. It automatically formats month names, weekday names, and sets the first day of the week based on BCP 47 language tags.

Global Language Support

ngxsmk-datepicker v2.4.0+ now features full localization synchronization for:

  • �� English (en)
  • �� German (de)
  • �� French (fr)
  • �� Spanish (es)
  • 🇸🇪 Swedish (sv)
  • �� Korean (ko)
  • �� Chinese (zh)
  • �� Japanese (ja)

Usage Example

<!-- Force German Locale -->
<ngxsmk-datepicker [locale]="'de-DE'"></ngxsmk-datepicker>

<!-- Swedish with YYYY-MM-DD format and Monday week start -->
<ngxsmk-datepicker [locale]="'sv-SE'"></ngxsmk-datepicker>

The component automatically uses ISO 8601 standards (Monday start) for European locales and appropriate regional date formats.

🖥️ Server-Side Rendering (SSR)

The datepicker is fully compatible with Angular Universal and server-side rendering:

  • ✅ All browser APIs are platform-checked
  • ✅ No window or document access during initialization
  • ✅ Works with partial hydration
  • ✅ Compatible with zoneless applications

See the SSR Guide for detailed setup instructions.

⌨️ Keyboard Navigation

The datepicker supports full keyboard navigation for accessibility:

Built-in Shortcuts

  • Arrow Keys (← → ↑ ↓): Navigate between dates
  • Page Up/Down: Navigate months (Shift + Page Up/Down for years)
  • Home/End: Jump to first/last day of month
  • Enter/Space: Select focused date
  • Escape: Close calendar (popover mode)
  • T: Select today's date
  • Y: Select yesterday
  • N: Select tomorrow
  • W: Select next week (7 days from today)
  • Tab: Navigate between interactive elements
  • ? (Shift + /): Toggle keyboard shortcuts help dialog

Custom Keyboard Shortcuts

You can add custom keyboard shortcuts using the hooks input or customShortcuts input:

import { DatepickerHooks, KeyboardShortcutContext } from "ngxsmk-datepicker";

const myHooks: DatepickerHooks = {
  handleShortcut: (event, context) => {
    if (event.ctrlKey && event.key === "1") {
      // Custom action
      return true; // Handled
    }
    return false; // Use default
  },
};
<ngxsmk-datepicker [hooks]="myHooks" [customShortcuts]="shortcuts" mode="single"> </ngxsmk-datepicker>

All date cells are keyboard accessible with proper ARIA attributes for screen readers. The component is built with accessibility in mind: keyboard navigation, ARIA roles and labels, and live regions for announcements. For details see API.md – Keyboard Support and the ARIA-related inputs (e.g. closeAriaLabel, clearAriaLabel) in the API reference.

See Extension Points Guide for detailed customization options.

🚀 Performance Optimizations

This library has been optimized for maximum performance:

  • 30% Smaller Bundle: Optimized build configuration and tree-shaking
  • 40% Faster Rendering: OnPush change detection strategy with proper triggers
  • 60% Faster Selection: Memoized date comparisons and debounced operations
  • Zero Dependencies: Standalone component with no external dependencies
  • Tree-shakable: Only import what you need
  • Memory Efficient: Cache size limits prevent memory leaks
  • Hardware Accelerated: CSS optimizations for smooth animations
  • Mobile Optimized: Touch-friendly interactions and responsive design

🐛 Bug Fixes & Improvements

Critical Updates (included since v2.2.6):

  • Timezone Support: Added full support for IANA timezones in "Today" calculation.
  • Date Validation: Fixed "Today" unselectable bug by normalizing minDate boundary checks.
  • Keyboard Shortcuts: Updated "Today" selection shortcut to use timezone-aware calculation.
  • Validation messages: User-facing i18n strings for invalid date, min/max; validationError output and on-screen error display
  • Change Detection: Fixed OnPush change detection issues with proper markForCheck() triggers
  • Date Comparison: Fixed null safety issues in date range comparisons
  • Memory Leaks: Added cache size limits to prevent memory leaks
  • Type Safety: Improved TypeScript types and null safety checks
  • Mobile UX: Enhanced mobile interactions and touch feedback
  • Performance: Optimized template bindings with memoized functions
  • Accessibility: Better focus states and keyboard navigation
  • Build System: Improved build configuration and optimization

Performance Enhancements:

  • 🚀 Optimized Bundle Size: Main bundle ~127KB (source maps excluded from published package)
  • 🚀 40% Faster Rendering: Enhanced OnPush change detection
  • 🚀 60% Faster Selection: Memoized date comparisons
  • 🚀 Memory Efficient: Cache size limits prevent memory leaks
  • 🚀 Hardware Accelerated: CSS optimizations for smooth animations
  • 🚀 Better Tree-Shaking: Optimized TypeScript compiler settings for smaller output
  • 🚀 Production Optimized: Source maps automatically removed from production builds

📱 Demo Application

A comprehensive demo application is included to showcase all features with a modern, polished UI:

# Clone the repository
git clone https://github.com/NGXSMK/ngxsmk-datepicker.git
cd ngxsmk-datepicker

# Install dependencies
npm install

# Run the demo app
npm start

The demo includes:

  • Modern UI Design: Beautiful glassmorphism effects, gradient themes, and polished visual hierarchy
  • Responsive Navigation: Modern navbar with search, theme toggle, and mobile-friendly menu
  • Enhanced Sidebar: Redesigned documentation sidebar with smooth animations and visual indicators
  • Signal Forms (Angular 21) with writable signal binding examples
  • Theming with CSS variables and Tailwind classes examples
  • Customization & A11y with weekStart, yearRange, labels, and aria examples
  • Holiday Provider Integration with US holidays
  • Single Date Selection with weekend restrictions
  • Inline Range Picker with toggle controls
  • Date Range with Time selection
  • Multiple Date Selection with action tracking
  • Programmatic Value Setting for all selection modes
  • Theme Toggle (Light/Dark mode) with automatic system preference detection
  • Customizable Calendar Views: Year-picker, decade-picker, timeline view, and time-slider view

🔧 Development

GitHub Actions

The project uses GitHub Actions for automated deployment:

  • Deploy Demo App: Automatically deploys the demo application to GitHub Pages on pushes to main/master branches
    • Workflow: .github/workflows/deploy-demo.yml
    • Triggers: Push to main/master or manual workflow dispatch
    • Builds and deploys the demo app to GitHub Pages

Building the Library

# Build the library (development)
npm run build

# Build optimized production version
# - Removes source maps automatically
# - Optimized TypeScript compilation
# - Enhanced tree-shaking
npm run build:optimized

# Analyze bundle size (excludes source maps)
npm run build:analyze

Build Output:

  • Main bundle: dist/ngxsmk-datepicker/fesm2022/ngxsmk-datepicker.mjs (~127KB)
  • Type definitions: dist/ngxsmk-datepicker/index.d.ts
  • Source maps: Automatically removed from production builds

Running Tests

# Run all tests (library + demo app)
npm test

# Run library tests only
npx ng test ngxsmk-datepicker --no-watch --browsers=ChromeHeadless

# Run specific test file
npx ng test ngxsmk-datepicker --include="**/issue-13.spec.ts"

# Run tests in watch mode
npm test -- --watch

Code Quality Improvements

The library now includes:

  • TypeScript Strict Mode: Enhanced type safety
  • ESLint Configuration: Code quality enforcement
  • Performance Monitoring: Built-in performance metrics
  • Memory Leak Prevention: Cache size limits and cleanup
  • Accessibility Testing: WCAG compliance checks
  • Mobile Testing: Touch interaction validation

📦 Package Structure

ngxsmk-datepicker/
├── projects/
│   ├── ngxsmk-datepicker/     # Main library
│   └── demo-app/              # Demo application
├── dist/                      # Built packages
├── docs/                      # Documentation
└── scripts/                   # Build scripts

🎯 Browser Support

  • Chrome 90+
  • Firefox 88+
  • Safari 14+
  • Edge 90+
  • Mobile Safari 14+
  • Chrome Mobile 90+

🗺️ Roadmap

Check out our Roadmap to see planned features, improvements, and how you can contribute. We're always looking for contributors, especially for issues labeled good-first-issue and help-wanted!

🤝 Contributions

We welcome and appreciate contributions from the community! Whether it's reporting a bug, suggesting a new feature, or submitting code, your help is valuable.

Development Setup

  1. Fork the repository on GitHub
  2. Clone your fork to your local machine
  3. Install dependencies: npm install
  4. Run the demo app: npm start
  5. Create a feature branch for your changes
  6. Commit your changes following conventional commits
  7. Submit a Pull Request to the main branch

Contribution Guidelines

  • Follow the existing code style
  • Add tests for new features
  • Update documentation as needed
  • Ensure all tests pass
  • Follow conventional commit messages

📄 Changelog

Recent: Use v3.0.3 on npm. The v2.3.x line adds side-by-side multi-calendar layouts, natural language typing, timezone selector UI dropdown, warning style selections, and strict TypeScript/AOT stability. Versions 2.0.10 and 2.0.11 are unpublished; use v2.1.1+ or v3.0.3.

For the full list of changes, see CHANGELOG.md.

🎨 Theming with TokiForge

Looking for a powerful theming solution for your Angular application? Check out TokiForge — an open-source modern design token & theme engine that provides runtime theme switching for React, Vue, Svelte, Angular, and any framework.

Why TokiForge?

  • SSR compatible — Works seamlessly with Angular Universal

Perfect for managing design tokens, creating theme systems, and implementing dark mode in your Angular applications!

👉 Learn more about TokiForge →


📜 License

MIT License - see LICENSE file for details.

🔍 SEO (demo site)

The hosted live demo build ships with meta tags (Open Graph, Twitter cards, hreflang, structured data) and locale-aware content for broader discovery. For GitHub/npm visibility—topics, awesome lists, StackBlitz, and security reporting—see Discoverability near the top of this README.

👨‍💻 Author

Sachin Dilshan

⭐ Support

If you find this library helpful, please consider:

  • Starring the repository
  • 🐛 Reporting bugs and issues
  • 💡 Suggesting new features
  • 🤝 Contributing code improvements
  • 📢 Sharing with the community