ngxsmk-datepicker 2.2.2 → 2.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,701 +1,702 @@
1
- # Integration Guides
2
-
3
- **Last updated:** March 3, 2026 · **Current stable:** v2.2.2
4
-
5
- This document provides integration examples for using ngxsmk-datepicker with popular frameworks and libraries.
6
-
7
- ## Table of Contents
8
-
9
- - [Theming](#theming)
10
- - [Accessibility](#accessibility)
11
- - [Input sanitization and CSP](#input-sanitization-and-csp)
12
- - [Angular Material](#angular-material)
13
- - [Ionic](#ionic)
14
- - [Tailwind CSS](#tailwind-css)
15
- - [React, Vue, & Vanilla JS (Web Components)](#react-vue--vanilla-js-web-components)
16
- - [Modals and overlays](#modals-and-overlays)
17
-
18
- ## Theming
19
-
20
- Two different mechanisms apply:
21
-
22
- - **Component input `[theme]`**: Accepts only `'light'` or `'dark'`. Use it to switch the built-in light/dark color set (e.g. `[theme]="'dark'"` or `[theme]="isDark() ? 'dark' : 'light'"`).
23
- - **ThemeBuilderService.applyTheme(themeObject, element?)**: Accepts a theme **object** (colors, spacing, borderRadius, shadows, etc.) and applies it as CSS variables to the given element (or globally if no element). Use it for custom brand colors and full design tokens. See [THEME-TOKENS.md](THEME-TOKENS.md).
24
- - When `element` is a **wrapper** (not the `ngxsmk-datepicker` host), the theme is applied to the wrapper and all descendant `ngxsmk-datepicker` elements so library defaults are overridden.
25
- - Use `theme.shadows.focus` to customize the input focus ring (e.g. `'0 0 0 3px color-mix(in srgb, var(--datepicker-primary-color) 15%, transparent)'`). Internal `--ngxsmk-color-*` variables are bridged from your theme colors automatically.
26
-
27
- Do not pass a theme object to the `[theme]` input; use `ThemeBuilderService` for that.
28
-
29
- ## Accessibility
30
-
31
- The datepicker is built with **accessibility in mind**: keyboard navigation (arrows, Enter, Escape, T/Y/N/W, etc.), ARIA roles and labels on interactive elements, and live regions for screen reader announcements. For keyboard shortcuts and ARIA options see [API.md – Keyboard Support](API.md#keyboard-support) and the ARIA-related inputs in the API reference.
32
-
33
- ## Input sanitization and CSP
34
-
35
- - **Input sanitization**: The library sanitizes user-provided date/time strings (e.g. from the input field) before use: it strips HTML delimiters, script handlers, and dangerous protocols. Template bindings do not use `innerHTML` for user content, so Angular's `DomSanitizer` is not required for normal usage.
36
- - **CSP**: If your app enforces a Content-Security-Policy, ensure it allows the same directives required by Angular (e.g. `script-src` for your app and Angular, `style-src` for component styles). The datepicker does not use `eval`, inline scripts, or nonce-based scripts; it uses standard Angular templates and styles. No extra CSP directives are required specifically for ngxsmk-datepicker.
37
-
38
- ## Angular Material
39
-
40
- The main `ngxsmk-datepicker` bundle does **not** import `@angular/material`, so non-Material apps are not forced to install it. If you use `mat-form-field`, install Material and add the directive as below.
41
-
42
- ### Installation
43
-
44
- ```bash
45
- npm install @angular/material @angular/cdk ngxsmk-datepicker
46
- ```
47
-
48
- ### Basic Integration (Standalone Components)
49
-
50
- **Recommended:** Use the **`ngxsmkMatFormFieldControl`** directive on the datepicker so `mat-form-field` finds it. Add this directive file to your project (e.g. `ngxsmk-mat-form-field.directive.ts`) so only Material apps pull in `@angular/material`:
51
-
52
- ```typescript
53
- // ngxsmk-mat-form-field.directive.ts
54
- import { Directive, forwardRef } from '@angular/core';
55
- import { MatFormFieldControl } from '@angular/material/form-field';
56
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
57
-
58
- @Directive({
59
- selector: 'ngxsmk-datepicker[ngxsmkMatFormFieldControl]',
60
- standalone: true,
61
- providers: [
62
- { provide: MatFormFieldControl, useExisting: forwardRef(() => NgxsmkDatepickerComponent) },
63
- ],
64
- })
65
- export class NgxsmkDatepickerMatFormFieldControlDirective {}
66
- ```
67
-
68
- Then in your component:
69
-
70
- ```typescript
71
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
72
- import { NgxsmkDatepickerMatFormFieldControlDirective } from './ngxsmk-mat-form-field.directive'; // your local file
73
- import { MatFormFieldModule } from '@angular/material/form-field';
74
-
75
- @Component({
76
- imports: [MatFormFieldModule, NgxsmkDatepickerComponent, NgxsmkDatepickerMatFormFieldControlDirective, ...],
77
- template: `
78
- <mat-form-field appearance="outline">
79
- <mat-label>Select Date</mat-label>
80
- <ngxsmk-datepicker ngxsmkMatFormFieldControl [value]="dateControl.value" (valueChange)="dateControl.setValue($event)" ... />
81
- </mat-form-field>
82
- `
83
- })
84
- ```
85
-
86
- If you see "mat-form-field must contain a MatFormFieldControl", add the directive to the datepicker host (see Issue #187).
87
-
88
- **Alternative (legacy / when directive is not used):** In `main.ts` before bootstrap, call `NgxsmkDatepickerComponent.withMaterialSupport(MatFormFieldControl)` (and optionally set `globalThis.__NGXSMK_MAT_FORM_FIELD_CONTROL__ = MatFormFieldControl`). Then use the datepicker inside `mat-form-field` without the directive. Prefer the directive above.
89
-
90
- ```typescript
91
- import { Component } from '@angular/core';
92
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
93
- import { MatFormFieldModule } from '@angular/material/form-field';
94
- import { MatInputModule } from '@angular/material/input';
95
- import { ReactiveFormsModule, FormControl } from '@angular/forms';
96
-
97
- @Component({
98
- selector: 'app-datepicker',
99
- standalone: true,
100
- imports: [
101
- NgxsmkDatepickerComponent,
102
- MatFormFieldModule,
103
- MatInputModule,
104
- ReactiveFormsModule
105
- ],
106
- template: `
107
- <mat-form-field appearance="outline">
108
- <mat-label>Select Date</mat-label>
109
- <ngxsmk-datepicker
110
- [value]="dateControl.value"
111
- (valueChange)="dateControl.setValue($event)"
112
- [theme]="materialTheme"
113
- placeholder="Choose a date">
114
- </ngxsmk-datepicker>
115
- </mat-form-field>
116
- `
117
- })
118
- export class DatepickerComponent {
119
- dateControl = new FormControl<Date | null>(null);
120
-
121
- materialTheme = {
122
- colors: {
123
- primary: '#3f51b5',
124
- background: '#ffffff',
125
- text: '#212121',
126
- border: '#e0e0e0',
127
- hover: '#f5f5f5'
128
- },
129
- borderRadius: {
130
- md: '4px'
131
- }
132
- };
133
- }
134
- ```
135
-
136
- **If you see "mat-form-field must contain a MatFormFieldControl":** Add the **`ngxsmkMatFormFieldControl`** directive to the datepicker (Option A above). Do not use `MAT_FORM_FIELD` or pass the wrong token; the directive is the supported path.
137
-
138
- ### Integration with Non-Standalone Components (NgModules)
139
-
140
- Add the same directive file (see snippet above) to your project, then import it in your NgModule:
141
-
142
- ```typescript
143
- import { NgModule } from '@angular/core';
144
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
145
- import { NgxsmkDatepickerMatFormFieldControlDirective } from './ngxsmk-mat-form-field.directive'; // your local file
146
- import { MatFormFieldModule } from '@angular/material/form-field';
147
- import { MatInputModule } from '@angular/material/input';
148
- import { ReactiveFormsModule } from '@angular/forms';
149
-
150
- @NgModule({
151
- imports: [
152
- NgxsmkDatepickerComponent,
153
- NgxsmkDatepickerMatFormFieldControlDirective,
154
- MatFormFieldModule,
155
- MatInputModule,
156
- ReactiveFormsModule
157
- ]
158
- })
159
- export class MyModule { }
160
- ```
161
-
162
- Use `ngxsmkMatFormFieldControl` on the datepicker in your templates.
163
-
164
- Then use it in your component:
165
-
166
- ```typescript
167
- import { Component } from '@angular/core';
168
- import { FormControl, FormGroup } from '@angular/forms';
169
-
170
- @Component({
171
- selector: 'app-material-form',
172
- template: `
173
- <form [formGroup]="myForm">
174
- <mat-form-field appearance="outline">
175
- <mat-label>Select Date</mat-label>
176
- <ngxsmk-datepicker
177
- mode="single"
178
- formControlName="date"
179
- placeholder="Choose a date">
180
- </ngxsmk-datepicker>
181
- </mat-form-field>
182
- </form>
183
- `
184
- })
185
- export class MaterialFormComponent {
186
- myForm = new FormGroup({
187
- date: new FormControl<Date | null>(null)
188
- });
189
- }
190
- ```
191
-
192
- ### Using with Reactive Forms
193
-
194
- ```typescript
195
- import { Component } from '@angular/core';
196
- import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
197
- import { MatFormFieldModule } from '@angular/material/form-field';
198
- import { MatInputModule } from '@angular/material/input';
199
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
200
-
201
- @Component({
202
- selector: 'app-material-form',
203
- standalone: true,
204
- imports: [
205
- ReactiveFormsModule,
206
- MatFormFieldModule,
207
- MatInputModule,
208
- NgxsmkDatepickerComponent
209
- ],
210
- template: `
211
- <form [formGroup]="myForm">
212
- <mat-form-field appearance="outline">
213
- <mat-label>Select Date</mat-label>
214
- <ngxsmk-datepicker
215
- mode="single"
216
- formControlName="date"
217
- placeholder="Choose a date">
218
- </ngxsmk-datepicker>
219
- </mat-form-field>
220
- </form>
221
- `
222
- })
223
- export class MaterialFormComponent {
224
- myForm = new FormGroup({
225
- date: new FormControl<Date | null>(null)
226
- });
227
- }
228
- ```
229
-
230
- ### With Material Datepicker Styling
231
-
232
- ```typescript
233
- import { Component, inject, ElementRef } from '@angular/core';
234
- import { NgxsmkDatepickerComponent, ThemeBuilderService } from 'ngxsmk-datepicker';
235
-
236
- @Component({
237
- selector: 'app-material-datepicker',
238
- standalone: true,
239
- imports: [NgxsmkDatepickerComponent],
240
- template: `
241
- <div class="material-datepicker-wrapper">
242
- <ngxsmk-datepicker
243
- [value]="selectedDate"
244
- (valueChange)="selectedDate = $event"
245
- theme="light"
246
- [classes]="materialClasses">
247
- </ngxsmk-datepicker>
248
- </div>
249
- `,
250
- styles: [`
251
- .material-datepicker-wrapper {
252
- width: 100%;
253
- }
254
-
255
- :host ::ng-deep .ngxsmk-input-group {
256
- border: 1px solid rgba(0, 0, 0, 0.12);
257
- border-radius: 4px;
258
- padding: 8px 12px;
259
- transition: border-color 0.2s;
260
- }
261
-
262
- :host ::ng-deep .ngxsmk-input-group:hover {
263
- border-color: rgba(0, 0, 0, 0.24);
264
- }
265
-
266
- :host ::ng-deep .ngxsmk-input-group:focus-within {
267
- border-color: #3f51b5;
268
- border-width: 2px;
269
- }
270
- `]
271
- })
272
- export class MaterialDatepickerComponent {
273
- private themeBuilder = inject(ThemeBuilderService);
274
- private hostEl = inject(ElementRef).nativeElement;
275
- selectedDate: Date | null = null;
276
-
277
- materialTheme = {
278
- colors: {
279
- primary: '#3f51b5',
280
- primaryContrast: '#ffffff',
281
- background: '#ffffff',
282
- text: '#212121',
283
- border: '#e0e0e0',
284
- hover: '#f5f5f5'
285
- },
286
- borderRadius: { md: '4px', lg: '8px' }
287
- };
288
-
289
- ngOnInit() {
290
- this.themeBuilder.applyTheme(this.materialTheme, this.hostEl);
291
- }
292
-
293
- materialClasses = {
294
- wrapper: 'material-datepicker',
295
- inputGroup: 'material-input-group',
296
- popover: 'material-popover'
297
- };
298
- }
299
- ```
300
-
301
- ## Ionic
302
-
303
- ### Installation
304
-
305
- ```bash
306
- npm install @ionic/angular ngxsmk-datepicker
307
- ```
308
-
309
- ### Basic Integration
310
-
311
- ```typescript
312
- import { Component } from '@angular/core';
313
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
314
- import { IonItem, IonLabel } from '@ionic/angular/standalone';
315
-
316
- @Component({
317
- selector: 'app-ionic-datepicker',
318
- standalone: true,
319
- imports: [NgxsmkDatepickerComponent, IonItem, IonLabel],
320
- template: `
321
- <ion-item>
322
- <ion-label position="stacked">Select Date</ion-label>
323
- <ngxsmk-datepicker
324
- [value]="selectedDate"
325
- (valueChange)="selectedDate = $event"
326
- [theme]="ionicTheme"
327
- [classes]="ionicClasses">
328
- </ngxsmk-datepicker>
329
- </ion-item>
330
- `,
331
- styles: [`
332
- :host ::ng-deep .ngxsmk-input-group {
333
- border: 1px solid var(--ion-color-medium);
334
- border-radius: 8px;
335
- background: var(--ion-background-color);
336
- }
337
-
338
- :host ::ng-deep .ngxsmk-popover-container {
339
- --datepicker-primary-color: var(--ion-color-primary);
340
- --datepicker-background: var(--ion-background-color);
341
- --datepicker-text-color: var(--ion-text-color);
342
- }
343
- `]
344
- })
345
- export class IonicDatepickerComponent {
346
- selectedDate: Date | null = null;
347
-
348
- ionicTheme = {
349
- colors: {
350
- primary: 'var(--ion-color-primary)',
351
- background: 'var(--ion-background-color)',
352
- text: 'var(--ion-text-color)',
353
- border: 'var(--ion-color-medium)',
354
- hover: 'var(--ion-color-light)'
355
- },
356
- borderRadius: {
357
- md: '8px',
358
- lg: '12px'
359
- }
360
- };
361
-
362
- ionicClasses = {
363
- wrapper: 'ionic-datepicker',
364
- inputGroup: 'ionic-input-group'
365
- };
366
- }
367
- ```
368
-
369
- ### With Ionic Popover
370
-
371
- ```typescript
372
- import { Component } from '@angular/core';
373
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
374
- import { PopoverController } from '@ionic/angular';
375
-
376
- @Component({
377
- selector: 'app-datepicker-popover',
378
- standalone: true,
379
- imports: [NgxsmkDatepickerComponent],
380
- template: `
381
- <ion-button (click)="openDatepicker()">
382
- Select Date
383
- </ion-button>
384
- `
385
- })
386
- export class DatepickerPopoverComponent {
387
- constructor(private popoverController: PopoverController) {}
388
-
389
- async openDatepicker() {
390
- const popover = await this.popoverController.create({
391
- component: NgxsmkDatepickerComponent,
392
- componentProps: {
393
- inline: true,
394
- value: new Date()
395
- },
396
- cssClass: 'datepicker-popover'
397
- });
398
-
399
- await popover.present();
400
- }
401
- }
402
- ```
403
-
404
- ## Tailwind CSS
405
-
406
- ### Installation
407
-
408
- ```bash
409
- npm install ngxsmk-datepicker tailwindcss
410
- ```
411
-
412
- ### Basic Integration
413
-
414
- ```typescript
415
- import { Component } from '@angular/core';
416
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
417
-
418
- @Component({
419
- selector: 'app-tailwind-datepicker',
420
- standalone: true,
421
- imports: [NgxsmkDatepickerComponent],
422
- template: `
423
- <div class="w-full max-w-md">
424
- <label class="block text-sm font-medium text-gray-700 mb-2">
425
- Select Date
426
- </label>
427
- <ngxsmk-datepicker
428
- [value]="selectedDate"
429
- (valueChange)="selectedDate = $event"
430
- [classes]="tailwindClasses">
431
- </ngxsmk-datepicker>
432
- </div>
433
- `,
434
- styles: [`
435
- :host ::ng-deep .ngxsmk-input-group {
436
- @apply border border-gray-300 rounded-lg px-4 py-2
437
- focus-within:ring-2 focus-within:ring-blue-500
438
- focus-within:border-blue-500 transition-all;
439
- }
440
-
441
- :host ::ng-deep .ngxsmk-display-input {
442
- @apply w-full outline-none text-gray-900;
443
- }
444
-
445
- :host ::ng-deep .ngxsmk-popover-container {
446
- @apply shadow-lg rounded-lg border border-gray-200;
447
- }
448
-
449
- :host ::ng-deep .ngxsmk-day-cell.selected {
450
- @apply bg-blue-500 text-white;
451
- }
452
-
453
- :host ::ng-deep .ngxsmk-day-cell:hover:not(.disabled) {
454
- @apply bg-blue-50;
455
- }
456
- `]
457
- })
458
- export class TailwindDatepickerComponent {
459
- selectedDate: Date | null = null;
460
-
461
- tailwindClasses = {
462
- wrapper: 'tailwind-datepicker',
463
- inputGroup: 'tailwind-input-group',
464
- popover: 'tailwind-popover'
465
- };
466
- }
467
- ```
468
-
469
- ### With Tailwind Utility Classes
470
-
471
- ```typescript
472
- import { Component } from '@angular/core';
473
- import { NgxsmkDatepickerComponent, ThemeBuilderService } from 'ngxsmk-datepicker';
474
- import { inject } from '@angular/core';
475
-
476
- @Component({
477
- selector: 'app-tailwind-themed-datepicker',
478
- standalone: true,
479
- imports: [NgxsmkDatepickerComponent],
480
- template: `
481
- <div class="container mx-auto p-4">
482
- <ngxsmk-datepicker
483
- [value]="selectedDate"
484
- (valueChange)="selectedDate = $event"
485
- [theme]="tailwindTheme"
486
- class="w-full">
487
- </ngxsmk-datepicker>
488
- </div>
489
- `
490
- })
491
- export class TailwindThemedDatepickerComponent {
492
- private themeBuilder = inject(ThemeBuilderService);
493
- selectedDate: Date | null = null;
494
-
495
- tailwindTheme = {
496
- colors: {
497
- primary: '#3b82f6', // Tailwind blue-500
498
- background: '#ffffff',
499
- text: '#111827', // gray-900
500
- border: '#d1d5db', // gray-300
501
- hover: '#f3f4f6' // gray-100
502
- },
503
- spacing: {
504
- sm: '0.5rem',
505
- md: '1rem',
506
- lg: '1.5rem'
507
- },
508
- borderRadius: {
509
- md: '0.5rem',
510
- lg: '0.75rem'
511
- }
512
- };
513
-
514
- constructor() {
515
- // Apply theme globally
516
- this.themeBuilder.applyTheme(this.tailwindTheme);
517
- }
518
- }
519
- ```
520
-
521
- ## Custom Styling Tips
522
-
523
- ### Using CSS Variables
524
-
525
- All datepicker styles can be customized using CSS variables:
526
-
527
- ```css
528
- :root {
529
- --datepicker-primary-color: #3b82f6;
530
- --datepicker-background: #ffffff;
531
- --datepicker-text-color: #111827;
532
- --datepicker-border-color: #d1d5db;
533
- --datepicker-spacing-md: 1rem;
534
- --datepicker-radius-md: 0.5rem;
535
- }
536
- ```
537
-
538
- ### Scoped Styling
539
-
540
- For component-specific styling:
541
-
542
- ```typescript
543
- @Component({
544
- styles: [`
545
- :host ::ng-deep .ngxsmk-datepicker-wrapper {
546
- /* Your custom styles */
547
- }
548
- `]
549
- })
550
- ```
551
-
552
- ### Theme Builder Service
553
-
554
- For dynamic theming:
555
-
556
- ```typescript
557
- import { ThemeBuilderService } from 'ngxsmk-datepicker';
558
-
559
- constructor(private themeBuilder: ThemeBuilderService) {
560
- const theme = {
561
- colors: {
562
- primary: '#your-color',
563
- // ... other colors
564
- }
565
- };
566
-
567
- // Apply globally
568
- this.themeBuilder.applyTheme(theme);
569
-
570
- // Or get CSS-in-JS style object
571
- const styles = this.themeBuilder.generateStyleObject(theme);
572
- }
573
- ```
574
-
575
- ## Best Practices
576
-
577
- 1. **Consistent Theming**: Use your framework's design tokens (colors, spacing, etc.) when creating themes
578
- 2. **Accessibility**: Ensure your custom themes maintain sufficient color contrast
579
- 3. **Responsive Design**: Test datepicker on different screen sizes, especially when using multi-calendar mode
580
- 4. **Performance**: Use `OnPush` change detection strategy when possible
581
- 5. **Localization**: Set the `locale` input to match your application's locale
582
-
583
- ## Troubleshooting
584
-
585
- ### Styles Not Applying
586
-
587
- - Ensure your styles are scoped correctly using `::ng-deep` or view encapsulation
588
- - Check that CSS variables are defined in the correct scope
589
- - Verify that the theme object structure matches the `DatepickerTheme` interface
590
-
591
- ### Integration Issues
592
-
593
- - Make sure all required peer dependencies are installed
594
- - Check that Angular version is compatible (Angular 17+)
595
- - Verify that standalone components are properly imported
596
-
597
- ## React, Vue, & Vanilla JS (Web Components)
598
-
599
- Since `ngxsmk-datepicker` is built as a highly isolated Angular library without heavy dependencies, it can be compiled into **Custom Web Components** using Angular Elements. This allows you to use exactly the same datepicker in React, Vue, Svelte, or Vanilla JavaScript.
600
-
601
- ### 1. Build as Custom Element
602
-
603
- You'll need a wrapper to bootstrap the Angular component as a custom element:
604
-
605
- ```typescript
606
- import { createApplication } from '@angular/platform-browser';
607
- import { createCustomElement } from '@angular/elements';
608
- import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
609
-
610
- (async () => {
611
- const app = await createApplication();
612
-
613
- const DatepickerElement = createCustomElement(NgxsmkDatepickerComponent, {
614
- injector: app.injector
615
- });
616
-
617
- customElements.define('ngxsmk-datepicker', DatepickerElement);
618
- })().catch(err => console.error(err));
619
- ```
620
-
621
- ### 2. Framework-specific Usage
622
-
623
- Once registered as `<ngxsmk-datepicker>`, you can use it in any framework.
624
-
625
- #### React Example
626
- ```jsx
627
- import React, { useEffect, useRef } from 'react';
628
-
629
- export function MyView() {
630
- const datepickerRef = useRef(null);
631
-
632
- useEffect(() => {
633
- // Listen to native custom events
634
- const picker = datepickerRef.current;
635
- const handleSelect = (e) => console.log('Selected:', e.detail);
636
-
637
- picker.addEventListener('dateSelect', handleSelect);
638
- return () => picker.removeEventListener('dateSelect', handleSelect);
639
- }, []);
640
-
641
- return (
642
- <ngxsmk-datepicker
643
- ref={datepickerRef}
644
- mode="range"
645
- theme="light">
646
- </ngxsmk-datepicker>
647
- );
648
- }
649
- ```
650
-
651
- #### Vue Example
652
- ```html
653
- <script setup>
654
- import { ref } from 'vue';
655
-
656
- const date = ref(null);
657
- const onDateSelect = (e) => {
658
- date.value = e.detail;
659
- };
660
- </script>
661
-
662
- <template>
663
- <ngxsmk-datepicker
664
- mode="single"
665
- @dateSelect="onDateSelect"
666
- ></ngxsmk-datepicker>
667
- </template>
668
- ```
669
-
670
- #### Vanilla JS
671
- ```html
672
- <ngxsmk-datepicker id="myPicker"></ngxsmk-datepicker>
673
-
674
- <script>
675
- const picker = document.getElementById('myPicker');
676
- picker.addEventListener('dateSelect', (e) => {
677
- alert('Date selected: ' + e.detail);
678
- });
679
- </script>
680
- ```
681
-
682
- ## Modals and overlays
683
-
684
- When using the datepicker inside a modal, dialog, or overlay (e.g. `role="dialog"`, Angular Material dialog, or a custom modal), set **`[appendToBody]="true"`** so the calendar popover is appended to `document.body`. This avoids stacking-context and overflow issues and ensures the popover positions correctly and does not flash in the wrong place on first open. The library can auto-detect some modal containers and enable append-to-body; for reliability we recommend setting it explicitly:
685
-
686
- ```html
687
- <ngxsmk-datepicker
688
- [appendToBody]="true"
689
- [(ngModel)]="myDate"
690
- placeholder="Pick a date">
691
- </ngxsmk-datepicker>
692
- ```
693
-
694
- See the demo app **Integrations** page for a full "Datepicker in a modal" example.
695
-
696
- ## Additional Resources
697
-
698
- - [API Documentation](./API.md)
699
- - [Theme Guide](./THEME-TOKENS.md)
700
- - [Locale Guide](./LOCALE-GUIDE.md)
701
-
1
+ # Integration Guides
2
+
3
+ **Last updated:** March 10, 2026 · **Current stable:** v2.2.6
4
+
5
+ This document provides integration examples for using ngxsmk-datepicker with popular frameworks and libraries.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Theming](#theming)
10
+ - [Accessibility](#accessibility)
11
+ - [Input sanitization and CSP](#input-sanitization-and-csp)
12
+ - [Angular Material](#angular-material)
13
+ - [Ionic](#ionic)
14
+ - [Tailwind CSS](#tailwind-css)
15
+ - [React, Vue, & Vanilla JS (Web Components)](#react-vue--vanilla-js-web-components)
16
+ - [Modals and overlays](#modals-and-overlays)
17
+
18
+ ## Theming
19
+
20
+ Two different mechanisms apply:
21
+
22
+ - **Component input `[theme]`**: Accepts only `'light'` or `'dark'`. Use it to switch the built-in light/dark color set (e.g. `[theme]="'dark'"` or `[theme]="isDark() ? 'dark' : 'light'"`).
23
+ - **ThemeBuilderService.applyTheme(themeObject, element?)**: Accepts a theme **object** (colors, spacing, borderRadius, shadows, etc.) and applies it as CSS variables to the given element (or globally if no element). Use it for custom brand colors and full design tokens. See [THEME-TOKENS.md](THEME-TOKENS.md).
24
+ - When `element` is a **wrapper** (not the `ngxsmk-datepicker` host), the theme is applied to the wrapper and all descendant `ngxsmk-datepicker` elements so library defaults are overridden.
25
+ - Use `theme.shadows.focus` to customize the input focus ring (e.g. `'0 0 0 3px color-mix(in srgb, var(--datepicker-primary-color) 15%, transparent)'`). Internal `--ngxsmk-color-*` variables are bridged from your theme colors automatically.
26
+
27
+ Do not pass a theme object to the `[theme]` input; use `ThemeBuilderService` for that.
28
+
29
+ ## Accessibility
30
+
31
+ The datepicker is built with **accessibility in mind**: keyboard navigation (arrows, Enter, Escape, T/Y/N/W, etc.), ARIA roles and labels on interactive elements, and live regions for screen reader announcements. For keyboard shortcuts and ARIA options see [API.md – Keyboard Support](API.md#keyboard-support) and the ARIA-related inputs in the API reference.
32
+
33
+ ## Input sanitization and CSP
34
+
35
+ - **Input sanitization**: The library sanitizes user-provided date/time strings (e.g. from the input field) before use: it strips HTML delimiters, script handlers, and dangerous protocols. Template bindings do not use `innerHTML` for user content, so Angular's `DomSanitizer` is not required for normal usage.
36
+ - **CSP**: If your app enforces a Content-Security-Policy, ensure it allows the same directives required by Angular (e.g. `script-src` for your app and Angular, `style-src` for component styles). The datepicker does not use `eval`, inline scripts, or nonce-based scripts; it uses standard Angular templates and styles. No extra CSP directives are required specifically for ngxsmk-datepicker.
37
+
38
+ ## Angular Material
39
+
40
+ The main `ngxsmk-datepicker` bundle does **not** import `@angular/material`, so non-Material apps are not forced to install it. If you use `mat-form-field`, install Material and add the directive as below.
41
+
42
+ ### Installation
43
+
44
+ ```bash
45
+ npm install @angular/material @angular/cdk ngxsmk-datepicker
46
+ ```
47
+
48
+ ### Basic Integration (Standalone Components)
49
+
50
+ **Recommended:** Use the **`ngxsmkMatFormFieldControl`** directive on the datepicker so `mat-form-field` finds it. Add this directive file to your project (e.g. `ngxsmk-mat-form-field.directive.ts`) so only Material apps pull in `@angular/material`:
51
+
52
+ ```typescript
53
+ // ngxsmk-mat-form-field.directive.ts
54
+ import { Directive, forwardRef } from '@angular/core';
55
+ import { MatFormFieldControl } from '@angular/material/form-field';
56
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
57
+
58
+ @Directive({
59
+ selector: 'ngxsmk-datepicker[ngxsmkMatFormFieldControl]',
60
+ standalone: true,
61
+ providers: [
62
+ { provide: MatFormFieldControl, useExisting: forwardRef(() => NgxsmkDatepickerComponent) },
63
+ ],
64
+ })
65
+ export class NgxsmkDatepickerMatFormFieldControlDirective {}
66
+ ```
67
+
68
+ Then in your component:
69
+
70
+ ```typescript
71
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
72
+ import { NgxsmkDatepickerMatFormFieldControlDirective } from './ngxsmk-mat-form-field.directive'; // your local file
73
+ import { MatFormFieldModule } from '@angular/material/form-field';
74
+
75
+ @Component({
76
+ imports: [MatFormFieldModule, NgxsmkDatepickerComponent, NgxsmkDatepickerMatFormFieldControlDirective, ...],
77
+ template: `
78
+ <mat-form-field appearance="outline">
79
+ <mat-label>Select Date</mat-label>
80
+ <ngxsmk-datepicker ngxsmkMatFormFieldControl [value]="dateControl.value" (valueChange)="dateControl.setValue($event)" ... />
81
+ </mat-form-field>
82
+ `
83
+ })
84
+ ```
85
+
86
+ If you see "mat-form-field must contain a MatFormFieldControl", add the directive to the datepicker host (see Issue #187).
87
+
88
+ **Alternative (legacy / when directive is not used):** In `main.ts` before bootstrap, call `NgxsmkDatepickerComponent.withMaterialSupport(MatFormFieldControl)` (and optionally set `globalThis.__NGXSMK_MAT_FORM_FIELD_CONTROL__ = MatFormFieldControl`). Then use the datepicker inside `mat-form-field` without the directive. Prefer the directive above.
89
+
90
+ ```typescript
91
+ import { Component } from '@angular/core';
92
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
93
+ import { MatFormFieldModule } from '@angular/material/form-field';
94
+ import { MatInputModule } from '@angular/material/input';
95
+ import { ReactiveFormsModule, FormControl } from '@angular/forms';
96
+
97
+ @Component({
98
+ selector: 'app-datepicker',
99
+ standalone: true,
100
+ imports: [
101
+ NgxsmkDatepickerComponent,
102
+ MatFormFieldModule,
103
+ MatInputModule,
104
+ ReactiveFormsModule
105
+ ],
106
+ template: `
107
+ <mat-form-field appearance="outline">
108
+ <mat-label>Select Date</mat-label>
109
+ <ngxsmk-datepicker
110
+ [value]="dateControl.value"
111
+ (valueChange)="dateControl.setValue($event)"
112
+ [theme]="materialTheme"
113
+ placeholder="Choose a date">
114
+ </ngxsmk-datepicker>
115
+ </mat-form-field>
116
+ `
117
+ })
118
+ export class DatepickerComponent {
119
+ dateControl = new FormControl<Date | null>(null);
120
+
121
+ materialTheme = {
122
+ colors: {
123
+ primary: '#3f51b5',
124
+ background: '#ffffff',
125
+ text: '#212121',
126
+ border: '#e0e0e0',
127
+ hover: '#f5f5f5'
128
+ },
129
+ borderRadius: {
130
+ md: '4px'
131
+ }
132
+ };
133
+ }
134
+ ```
135
+
136
+ **If you see "mat-form-field must contain a MatFormFieldControl":** Add the **`ngxsmkMatFormFieldControl`** directive to the datepicker (Option A above). Do not use `MAT_FORM_FIELD` or pass the wrong token; the directive is the supported path.
137
+
138
+ ### Integration with Non-Standalone Components (NgModules)
139
+
140
+ Add the same directive file (see snippet above) to your project, then import it in your NgModule:
141
+
142
+ ```typescript
143
+ import { NgModule } from '@angular/core';
144
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
145
+ import { NgxsmkDatepickerMatFormFieldControlDirective } from './ngxsmk-mat-form-field.directive'; // your local file
146
+ import { MatFormFieldModule } from '@angular/material/form-field';
147
+ import { MatInputModule } from '@angular/material/input';
148
+ import { ReactiveFormsModule } from '@angular/forms';
149
+
150
+ @NgModule({
151
+ imports: [
152
+ NgxsmkDatepickerComponent,
153
+ NgxsmkDatepickerMatFormFieldControlDirective,
154
+ MatFormFieldModule,
155
+ MatInputModule,
156
+ ReactiveFormsModule
157
+ ]
158
+ })
159
+ export class MyModule { }
160
+ ```
161
+
162
+ Use `ngxsmkMatFormFieldControl` on the datepicker in your templates.
163
+
164
+ Then use it in your component:
165
+
166
+ ```typescript
167
+ import { Component } from '@angular/core';
168
+ import { FormControl, FormGroup } from '@angular/forms';
169
+
170
+ @Component({
171
+ selector: 'app-material-form',
172
+ template: `
173
+ <form [formGroup]="myForm">
174
+ <mat-form-field appearance="outline">
175
+ <mat-label>Select Date</mat-label>
176
+ <ngxsmk-datepicker
177
+ mode="single"
178
+ formControlName="date"
179
+ placeholder="Choose a date">
180
+ </ngxsmk-datepicker>
181
+ </mat-form-field>
182
+ </form>
183
+ `
184
+ })
185
+ export class MaterialFormComponent {
186
+ myForm = new FormGroup({
187
+ date: new FormControl<Date | null>(null)
188
+ });
189
+ }
190
+ ```
191
+
192
+ ### Using with Reactive Forms
193
+
194
+ ```typescript
195
+ import { Component } from '@angular/core';
196
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
197
+ import { MatFormFieldModule } from '@angular/material/form-field';
198
+ import { MatInputModule } from '@angular/material/input';
199
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
200
+
201
+ @Component({
202
+ selector: 'app-material-form',
203
+ standalone: true,
204
+ imports: [
205
+ ReactiveFormsModule,
206
+ MatFormFieldModule,
207
+ MatInputModule,
208
+ NgxsmkDatepickerComponent
209
+ ],
210
+ template: `
211
+ <form [formGroup]="myForm">
212
+ <mat-form-field appearance="outline">
213
+ <mat-label>Select Date</mat-label>
214
+ <ngxsmk-datepicker
215
+ mode="single"
216
+ formControlName="date"
217
+ placeholder="Choose a date">
218
+ </ngxsmk-datepicker>
219
+ </mat-form-field>
220
+ </form>
221
+ `
222
+ })
223
+ export class MaterialFormComponent {
224
+ myForm = new FormGroup({
225
+ date: new FormControl<Date | null>(null)
226
+ });
227
+ }
228
+ ```
229
+
230
+ ### With Material Datepicker Styling
231
+
232
+ ```typescript
233
+ import { Component, inject, ElementRef } from '@angular/core';
234
+ import { NgxsmkDatepickerComponent, ThemeBuilderService } from 'ngxsmk-datepicker';
235
+
236
+ @Component({
237
+ selector: 'app-material-datepicker',
238
+ standalone: true,
239
+ imports: [NgxsmkDatepickerComponent],
240
+ template: `
241
+ <div class="material-datepicker-wrapper">
242
+ <ngxsmk-datepicker
243
+ [value]="selectedDate"
244
+ (valueChange)="selectedDate = $event"
245
+ theme="light"
246
+ [classes]="materialClasses">
247
+ </ngxsmk-datepicker>
248
+ </div>
249
+ `,
250
+ styles: [`
251
+ .material-datepicker-wrapper {
252
+ width: 100%;
253
+ }
254
+
255
+ :host ::ng-deep .ngxsmk-input-group {
256
+ border: 1px solid rgba(0, 0, 0, 0.12);
257
+ border-radius: 4px;
258
+ padding: 8px 12px;
259
+ transition: border-color 0.2s;
260
+ }
261
+
262
+ :host ::ng-deep .ngxsmk-input-group:hover {
263
+ border-color: rgba(0, 0, 0, 0.24);
264
+ }
265
+
266
+ :host ::ng-deep .ngxsmk-input-group:focus-within {
267
+ border-color: #3f51b5;
268
+ border-width: 2px;
269
+ }
270
+ `]
271
+ })
272
+ export class MaterialDatepickerComponent {
273
+ private themeBuilder = inject(ThemeBuilderService);
274
+ private hostEl = inject(ElementRef).nativeElement;
275
+ selectedDate: Date | null = null;
276
+
277
+ materialTheme = {
278
+ colors: {
279
+ primary: '#3f51b5',
280
+ primaryContrast: '#ffffff',
281
+ background: '#ffffff',
282
+ text: '#212121',
283
+ border: '#e0e0e0',
284
+ hover: '#f5f5f5'
285
+ },
286
+ borderRadius: { md: '4px', lg: '8px' }
287
+ };
288
+
289
+ ngOnInit() {
290
+ this.themeBuilder.applyTheme(this.materialTheme, this.hostEl);
291
+ }
292
+
293
+ materialClasses = {
294
+ wrapper: 'material-datepicker',
295
+ inputGroup: 'material-input-group',
296
+ popover: 'material-popover'
297
+ };
298
+ }
299
+ ```
300
+
301
+ ## Ionic
302
+
303
+ ### Installation
304
+
305
+ ```bash
306
+ npm install @ionic/angular ngxsmk-datepicker
307
+ ```
308
+
309
+ ### Basic Integration
310
+
311
+ ```typescript
312
+ import { Component } from '@angular/core';
313
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
314
+ import { IonItem, IonLabel } from '@ionic/angular/standalone';
315
+
316
+ @Component({
317
+ selector: 'app-ionic-datepicker',
318
+ standalone: true,
319
+ imports: [NgxsmkDatepickerComponent, IonItem, IonLabel],
320
+ template: `
321
+ <ion-item>
322
+ <ion-label position="stacked">Select Date</ion-label>
323
+ <ngxsmk-datepicker
324
+ [value]="selectedDate"
325
+ (valueChange)="selectedDate = $event"
326
+ [theme]="ionicTheme"
327
+ [classes]="ionicClasses">
328
+ </ngxsmk-datepicker>
329
+ </ion-item>
330
+ `,
331
+ styles: [`
332
+ :host ::ng-deep .ngxsmk-input-group {
333
+ border: 1px solid var(--ion-color-medium);
334
+ border-radius: 8px;
335
+ background: var(--ion-background-color);
336
+ }
337
+
338
+ :host ::ng-deep .ngxsmk-popover-container {
339
+ --datepicker-primary-color: var(--ion-color-primary);
340
+ --datepicker-background: var(--ion-background-color);
341
+ --datepicker-text-color: var(--ion-text-color);
342
+ }
343
+ `]
344
+ })
345
+ export class IonicDatepickerComponent {
346
+ selectedDate: Date | null = null;
347
+
348
+ ionicTheme = {
349
+ colors: {
350
+ primary: 'var(--ion-color-primary)',
351
+ background: 'var(--ion-background-color)',
352
+ text: 'var(--ion-text-color)',
353
+ border: 'var(--ion-color-medium)',
354
+ hover: 'var(--ion-color-light)'
355
+ },
356
+ borderRadius: {
357
+ md: '8px',
358
+ lg: '12px'
359
+ }
360
+ };
361
+
362
+ ionicClasses = {
363
+ wrapper: 'ionic-datepicker',
364
+ inputGroup: 'ionic-input-group'
365
+ };
366
+ }
367
+ ```
368
+
369
+ ### With Ionic Popover
370
+
371
+ ```typescript
372
+ import { Component } from '@angular/core';
373
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
374
+ import { PopoverController } from '@ionic/angular';
375
+
376
+ @Component({
377
+ selector: 'app-datepicker-popover',
378
+ standalone: true,
379
+ imports: [NgxsmkDatepickerComponent],
380
+ template: `
381
+ <ion-button (click)="openDatepicker()">
382
+ Select Date
383
+ </ion-button>
384
+ `
385
+ })
386
+ export class DatepickerPopoverComponent {
387
+ constructor(private popoverController: PopoverController) {}
388
+
389
+ async openDatepicker() {
390
+ const popover = await this.popoverController.create({
391
+ component: NgxsmkDatepickerComponent,
392
+ componentProps: {
393
+ inline: true,
394
+ value: new Date()
395
+ },
396
+ cssClass: 'datepicker-popover'
397
+ });
398
+
399
+ await popover.present();
400
+ }
401
+ }
402
+ ```
403
+
404
+ ## Tailwind CSS
405
+
406
+ ### Installation
407
+
408
+ ```bash
409
+ npm install ngxsmk-datepicker tailwindcss
410
+ ```
411
+
412
+ ### Basic Integration
413
+
414
+ ```typescript
415
+ import { Component } from '@angular/core';
416
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
417
+
418
+ @Component({
419
+ selector: 'app-tailwind-datepicker',
420
+ standalone: true,
421
+ imports: [NgxsmkDatepickerComponent],
422
+ template: `
423
+ <div class="w-full max-w-md">
424
+ <label class="block text-sm font-medium text-gray-700 mb-2">
425
+ Select Date
426
+ </label>
427
+ <ngxsmk-datepicker
428
+ [value]="selectedDate"
429
+ (valueChange)="selectedDate = $event"
430
+ [classes]="tailwindClasses">
431
+ </ngxsmk-datepicker>
432
+ </div>
433
+ `,
434
+ styles: [`
435
+ :host ::ng-deep .ngxsmk-input-group {
436
+ @apply border border-gray-300 rounded-lg px-4 py-2
437
+ focus-within:ring-2 focus-within:ring-blue-500
438
+ focus-within:border-blue-500 transition-all;
439
+ }
440
+
441
+ :host ::ng-deep .ngxsmk-display-input {
442
+ @apply w-full outline-none text-gray-900;
443
+ }
444
+
445
+ :host ::ng-deep .ngxsmk-popover-container {
446
+ @apply shadow-lg rounded-lg border border-gray-200;
447
+ }
448
+
449
+ :host ::ng-deep .ngxsmk-day-cell.selected {
450
+ @apply bg-blue-500 text-white;
451
+ }
452
+
453
+ :host ::ng-deep .ngxsmk-day-cell:hover:not(.disabled) {
454
+ @apply bg-blue-50;
455
+ }
456
+ `]
457
+ })
458
+ export class TailwindDatepickerComponent {
459
+ selectedDate: Date | null = null;
460
+
461
+ tailwindClasses = {
462
+ wrapper: 'tailwind-datepicker',
463
+ inputGroup: 'tailwind-input-group',
464
+ popover: 'tailwind-popover'
465
+ };
466
+ }
467
+ ```
468
+
469
+ ### With Tailwind Utility Classes
470
+
471
+ ```typescript
472
+ import { Component } from '@angular/core';
473
+ import { NgxsmkDatepickerComponent, ThemeBuilderService } from 'ngxsmk-datepicker';
474
+ import { inject } from '@angular/core';
475
+
476
+ @Component({
477
+ selector: 'app-tailwind-themed-datepicker',
478
+ standalone: true,
479
+ imports: [NgxsmkDatepickerComponent],
480
+ template: `
481
+ <div class="container mx-auto p-4">
482
+ <ngxsmk-datepicker
483
+ [value]="selectedDate"
484
+ (valueChange)="selectedDate = $event"
485
+ [theme]="tailwindTheme"
486
+ class="w-full">
487
+ </ngxsmk-datepicker>
488
+ </div>
489
+ `
490
+ })
491
+ export class TailwindThemedDatepickerComponent {
492
+ private themeBuilder = inject(ThemeBuilderService);
493
+ selectedDate: Date | null = null;
494
+
495
+ tailwindTheme = {
496
+ colors: {
497
+ primary: '#3b82f6', // Tailwind blue-500
498
+ background: '#ffffff',
499
+ text: '#111827', // gray-900
500
+ border: '#d1d5db', // gray-300
501
+ hover: '#f3f4f6' // gray-100
502
+ },
503
+ spacing: {
504
+ sm: '0.5rem',
505
+ md: '1rem',
506
+ lg: '1.5rem'
507
+ },
508
+ borderRadius: {
509
+ md: '0.5rem',
510
+ lg: '0.75rem'
511
+ }
512
+ };
513
+
514
+ constructor() {
515
+ // Apply theme globally
516
+ this.themeBuilder.applyTheme(this.tailwindTheme);
517
+ }
518
+ }
519
+ ```
520
+
521
+ ## Custom Styling Tips
522
+
523
+ ### Using CSS Variables
524
+
525
+ All datepicker styles can be customized using CSS variables:
526
+
527
+ ```css
528
+ :root {
529
+ --datepicker-primary-color: #3b82f6;
530
+ --datepicker-background: #ffffff;
531
+ --datepicker-text-color: #111827;
532
+ --datepicker-border-color: #d1d5db;
533
+ --datepicker-spacing-md: 1rem;
534
+ --datepicker-radius-md: 0.5rem;
535
+ }
536
+ ```
537
+
538
+ ### Scoped Styling
539
+
540
+ For component-specific styling:
541
+
542
+ ```typescript
543
+ @Component({
544
+ styles: [`
545
+ :host ::ng-deep .ngxsmk-datepicker-wrapper {
546
+ /* Your custom styles */
547
+ }
548
+ `]
549
+ })
550
+ ```
551
+
552
+ ### Theme Builder Service
553
+
554
+ For dynamic theming:
555
+
556
+ ```typescript
557
+ import { ThemeBuilderService } from 'ngxsmk-datepicker';
558
+
559
+ constructor(private themeBuilder: ThemeBuilderService) {
560
+ const theme = {
561
+ colors: {
562
+ primary: '#your-color',
563
+ // ... other colors
564
+ }
565
+ };
566
+
567
+ // Apply globally
568
+ this.themeBuilder.applyTheme(theme);
569
+
570
+ // Or get CSS-in-JS style object
571
+ const styles = this.themeBuilder.generateStyleObject(theme);
572
+ }
573
+ ```
574
+
575
+ ## Best Practices
576
+
577
+ 1. **Consistent Theming**: Use your framework's design tokens (colors, spacing, etc.) when creating themes
578
+ 2. **Accessibility**: Ensure your custom themes maintain sufficient color contrast
579
+ 3. **Responsive Design**: Test datepicker on different screen sizes, especially when using multi-calendar mode
580
+ 4. **Performance**: Use `OnPush` change detection strategy when possible
581
+ 5. **Localization**: Set the `locale` input to match your application's locale
582
+
583
+ ## Troubleshooting
584
+
585
+ ### Styles Not Applying
586
+
587
+ - Ensure your styles are scoped correctly using `::ng-deep` or view encapsulation
588
+ - Check that CSS variables are defined in the correct scope
589
+ - Verify that the theme object structure matches the `DatepickerTheme` interface
590
+
591
+ ### Integration Issues
592
+
593
+ - Make sure all required peer dependencies are installed
594
+ - Check that Angular version is compatible (Angular 17+)
595
+ - Verify that standalone components are properly imported
596
+
597
+ ## React, Vue, & Vanilla JS (Web Components)
598
+
599
+ Since `ngxsmk-datepicker` is built as a highly isolated Angular library without heavy dependencies, it can be compiled into **Custom Web Components** using Angular Elements. This allows you to use exactly the same datepicker in React, Vue, Svelte, or Vanilla JavaScript.
600
+
601
+ ### 1. Build as Custom Element
602
+
603
+ You'll need a wrapper to bootstrap the Angular component as a custom element:
604
+
605
+ ```typescript
606
+ import { createApplication } from '@angular/platform-browser';
607
+ import { createCustomElement } from '@angular/elements';
608
+ import { NgxsmkDatepickerComponent } from 'ngxsmk-datepicker';
609
+
610
+ (async () => {
611
+ const app = await createApplication();
612
+
613
+ const DatepickerElement = createCustomElement(NgxsmkDatepickerComponent, {
614
+ injector: app.injector
615
+ });
616
+
617
+ customElements.define('ngxsmk-datepicker', DatepickerElement);
618
+ })().catch(err => console.error(err));
619
+ ```
620
+
621
+ ### 2. Framework-specific Usage
622
+
623
+ Once registered as `<ngxsmk-datepicker>`, you can use it in any framework.
624
+
625
+ #### React Example
626
+ ```jsx
627
+ import React, { useEffect, useRef } from 'react';
628
+
629
+ export function MyView() {
630
+ const datepickerRef = useRef(null);
631
+
632
+ useEffect(() => {
633
+ // Listen to native custom events
634
+ const picker = datepickerRef.current;
635
+ const handleSelect = (e) => console.log('Selected:', e.detail);
636
+
637
+ picker.addEventListener('dateSelect', handleSelect);
638
+ return () => picker.removeEventListener('dateSelect', handleSelect);
639
+ }, []);
640
+
641
+ return (
642
+ <ngxsmk-datepicker
643
+ ref={datepickerRef}
644
+ mode="range"
645
+ theme="light">
646
+ </ngxsmk-datepicker>
647
+ );
648
+ }
649
+ ```
650
+
651
+ #### Vue Example
652
+ ```html
653
+ <script setup>
654
+ import { ref } from 'vue';
655
+
656
+ const date = ref(null);
657
+ const onDateSelect = (e) => {
658
+ date.value = e.detail;
659
+ };
660
+ </script>
661
+
662
+ <template>
663
+ <ngxsmk-datepicker
664
+ mode="single"
665
+ @dateSelect="onDateSelect"
666
+ ></ngxsmk-datepicker>
667
+ </template>
668
+ ```
669
+
670
+ #### Vanilla JS
671
+ ```html
672
+ <ngxsmk-datepicker id="myPicker"></ngxsmk-datepicker>
673
+
674
+ <script>
675
+ const picker = document.getElementById('myPicker');
676
+ picker.addEventListener('dateSelect', (e) => {
677
+ alert('Date selected: ' + e.detail);
678
+ });
679
+ </script>
680
+ ```
681
+
682
+ ## Modals and overlays
683
+
684
+ When using the datepicker inside a modal, dialog, or overlay (e.g. `role="dialog"`, Angular Material dialog, or a custom modal), set **`[appendToBody]="true"`** so the calendar popover is appended to `document.body`. This avoids stacking-context and overflow issues and ensures the popover positions correctly and does not flash in the wrong place on first open. The library can auto-detect some modal containers and enable append-to-body; for reliability we recommend setting it explicitly:
685
+
686
+ ```html
687
+ <ngxsmk-datepicker
688
+ [appendToBody]="true"
689
+ [(ngModel)]="myDate"
690
+ placeholder="Pick a date">
691
+ </ngxsmk-datepicker>
692
+ ```
693
+
694
+ See the demo app **Integrations** page for a full "Datepicker in a modal" example.
695
+
696
+ ## Additional Resources
697
+
698
+ - [API Documentation](./API.md)
699
+ - [Theme Guide](./THEME-TOKENS.md)
700
+ - [Locale Guide](./LOCALE-GUIDE.md)
701
+
702
+