API reference
The default surface is tng-datepicker. When you need custom markup, use createDatepickerController(...), bindTngDatepicker(...), and the datepicker helper directives instead of wiring keyboard, focus, and ARIA behavior by hand.
The wrapper intentionally sets a few opinionated defaults on top of the controller, notably closeOnSelect, trapFocus, and autoCommitView.
tng-datepicker (component)
Wrapper attachment
html
<tng-datepicker
[defaultValue]="'2024-04-22'"
[minDate]="'2024-04-01'"
[maxDate]="'2026-03-31'"
selectionMode="single"
ariaLabel="Invoice date"
></tng-datepicker>
Selection and value
| Property | Type | Default | Details |
|---|---|---|---|
defaultValue | TngDateSelectionInput<TDate> | undefined | undefined | Sets the uncontrolled initial selection. |
value | TngDateSelectionInput<TDate> | undefined | undefined | Controls the committed selection from the outside. |
selectionMode | 'single' | 'range' | 'multiple' | 'single' | Changes the value model and selection behavior without changing the wrapper UI contract. |
allowDeselect | boolean | false | Lets a second click clear the current selection in single mode. |
minDate / maxDate | TngDateInputValue<TDate> | undefined | undefined | Disables out-of-range days, months, and years. |
disableDate | ((date: TDate) => boolean) | null | null | Disables individual dates inside the otherwise valid range. |
today | TngDateInputValue<TDate> | undefined | undefined | Overrides which date is marked as today in the grid. |
Interaction and behavior
| Property | Type | Default | Details |
|---|---|---|---|
allowManualInput | boolean | true | Allows typing directly into the field and committing valid values. |
autoCommitView | boolean | false | Controls whether the wrapper should auto-commit when drilling between year, month, and day views. |
closeOnEscape | boolean | true | Closes the popup when Escape is pressed. |
closeOnOutsideClick | boolean | true | Dismisses the popup when pointer or focus moves outside. |
closeOnSelect | boolean | true | Closes after a committed date selection. |
closeOthersOnOpen | boolean | false | Asks other registered datepickers to close when this one opens. |
restoreFocus | boolean | true | Restores focus to the trigger after the popup closes. |
showOutsideDays | boolean | true | Keeps adjacent-month days visible in day view. |
trapFocus | boolean | true | Keeps focus inside the popup while it is open. |
weekStartsOn | TngWeekdayIndex | 0 | Overrides the locale-derived start of week. |
Overlay and layout
| Property | Type | Default | Details |
|---|---|---|---|
defaultOpen | boolean | false | Sets the uncontrolled initial open state. |
open | boolean | undefined | undefined | Controls the popup state from the outside. |
placement | 'auto' | 'bottom' | 'top' | 'auto' | Auto-flips the popup when there is not enough room below the field. |
overlayRuntime | TngOverlayRuntime | null | undefined | Internal runtime | Lets advanced apps share an overlay layer registry across surfaces. |
overlaySize | number | 320 | Sets the popup width used by the wrapper overlay positioning logic. |
yearPageSize | number | 24 | Controls how many years are shown per year page. |
direction | 'ltr' | 'rtl' | 'ltr' | Flips navigation semantics and keyboard movement for RTL flows. |
Accessibility and presentation
| Property | Type | Default | Details |
|---|---|---|---|
adapter | TngDateAdapter<TDate> | undefined | Default date adapter | Controls parsing, formatting, and visible month or period labels. |
ariaDescribedBy | string | null | null | Forwards an external description id to the host. |
ariaLabel | string | null | null | Sets a root accessible name when no visible label is present. |
ariaLabelledBy | string | null | null | Points the host at an external labeling element. |
disabled | boolean | false | Disables the field, trigger, and all calendar interaction. |
fullWidth | boolean | true | Makes the host fill the available inline size. |
id | string | null | null | Seeds the generated input id and overlay relationship ids. |
inputAriaLabel | string | 'Date input' | Labels the editable text input itself. |
invalid | boolean | false | Forces invalid styling in addition to manual input validation state. |
locale | string | Angular LOCALE_ID | Drives weekday names, month labels, and adapter locale defaults. |
placeholder | string | 'MM-DD-YYYY' | Changes the visible hint only. Parsing still comes from the adapter. |
readonly | boolean | false | Makes the text field read-only while still allowing popup selection. |
Outputs
| Output | Type | Details |
|---|---|---|
valueChange | TngDateValue<TDate> | Emits after click, keyboard commit, or a successful manual input commit. |
openChange | boolean | Emits whenever the popup opens or closes. |
closed | TngDatepickerCloseReason | Reports escape, outside, programmatic, or select close reasons. |
activeDateChange | TDate | Emits as keyboard focus moves through the calendar model. |
viewChange | 'day' | 'month' | 'year' | Tracks the current visible panel. |
monthChange | TDate | Emits when the visible month block changes. |
yearChange | number | Emits when the visible year page anchor changes. |
Wrapper instance methods
| Method | Purpose |
|---|---|
clear() | Clears the current selection for the active selection mode and returns the wrapper to day view. |
close(reason?) | Programmatically closes the popup with an optional close reason. |
openDatepicker() | Programmatically opens the popup. |
showDaysPanel() / showMonthsPanel() / showYearsPanel() | Drives the visible panel explicitly when the default drill-down flow is not enough. |
toggleOpen() | Toggles the popup state. |
Headless binding layer
Controller + Angular binding
ts
import { bindTngDatepicker, createDatepickerController } from '@tailng-ui/primitives';
readonly controller = createDatepickerController<Date>({
ownerDocument: document,
value: '2024-04-22',
today: '2024-04-18',
minDate: '2024-04-01',
maxDate: '2026-03-31',
closeOnSelect: true,
trapFocus: true,
});
readonly datepicker = bindTngDatepicker(this.controller);
Field + overlay wiring
html
<section [tngDatepickerHost]="controller">
<div data-slot="datepicker-field">
<div #anchorShell>
<div
data-slot="datepicker-input-shell"
[attr.data-invalid]="datepicker.outputs().validationError !== null ? 'true' : null"
[attr.data-open]="datepicker.outputs().getTriggerAttributes()['data-open']"
>
<input [tngDatepickerInput]="controller" type="text" placeholder="MM-DD-YYYY" />
<button [tngDatepickerTrigger]="controller" type="button">Open</button>
</div>
<section [tngDatepickerOverlay]="controller" [tngDatepickerOverlayAnchor]="anchorShell">
<button [tngDatepickerPrevButton]="controller" type="button">‹</button>
<button [tngDatepickerPeriodButton]="controller" type="button">
{{ datepicker.periodLabel() }}
</button>
<button [tngDatepickerNextButton]="controller" type="button">›</button>
<div [tngDatepickerDayGrid]="controller">
@for (cell of datepicker.outputs().cells; track cell.id) {
<button [tngDatepickerDayCell]="cell" type="button">{{ cell.label }}</button>
}
</div>
</section>
</div>
</div>
</section>
| Helper | Purpose |
|---|---|
bindTngDatepicker(controller) | Returns signals for outputs() and periodLabel() so Angular templates can stay declarative. |
[tngDatepickerHost] | Applies the public root attributes such as data-open, data-view, and ARIA labels. |
[tngDatepickerInput] / [tngDatepickerTrigger] | Forward manual input editing, trigger registration, and wrapper-grade open and keyboard behavior. |
[tngDatepickerOverlay] | Ports the popup to document.body, syncs public overlay attributes, and keeps focus and positioning aligned. |
[tngDatepickerPrevButton] / [tngDatepickerNextButton] / [tngDatepickerPeriodButton] | Own the standard navigation and drill-down flow without per-view branching in your component. |
[tngDatepickerDayGrid] / [tngDatepickerDayCell] | Forward day-grid keyboarding, click handling, hover range behavior, and the public day-cell state hooks. |
[tngDatepickerMonthGrid] / [tngDatepickerMonthOption] / [tngDatepickerYearGrid] / [tngDatepickerYearOption] | Handle month and year picker keyboarding and selection while preserving the public slot contract. |
Advanced controller options
The wrapper covers the common surface. These options are available when you work with the controller directly.
| Option | Type | Default | Details |
|---|---|---|---|
initialView | 'day' | 'month' | 'year' | 'day' | Starts the controller on a different panel than the wrapper exposes by default. |
overlayMode | 'overlay' | 'push' | 'side' | 'overlay' | Changes how the controller models overlay layout when you are fully headless. |
position | 'start' | 'center' | 'end' | 'start' | Changes overlay alignment relative to the field in headless layouts. |
focusStrategy | 'active-descendant' | 'roving' | 'roving' | Lets advanced compositions opt into a different grid focus model. |
maxSelections | number | null | null | Caps the number of selected values in multiple mode. |
onPartialInputCommit | boolean | false | Allows partial manual input commits in advanced headless flows. |
preserveViewOnOpenClose | boolean | true | Keeps the current panel when reopening instead of always returning to day view. |
skipDisabled | boolean | true | Controls whether keyboard movement jumps across disabled dates. |
Controller methods
| Method | Purpose |
|---|---|
getOutputs() / getState() | Read the live render model or the lower-level mutable state snapshot. |
open() / close() / toggleOpen() | Own popup visibility when you are not using the wrapper. |
setInputText(...) / commitInputText() / parseInputText(...) | Support manual editing with adapter validation and bound checks. |
selectDate(...) / clear() / setValue(...) | Own the committed selection state directly. |
showYearsPanel() / showMonthsPanel() / showDaysPanel() | Drive the visible panel explicitly. |
setConfig(...) | Reconfigures the controller after creation for advanced custom integrations. |
subscribe(...) | Exposes low-level controller events when the template bindings are not enough. |