Getting StartedInstallation and setup guides 6
FormInput and selection components 26
LayoutWorkflow and structural layout components 10
NavigationMenu surfaces and hierarchical actions 7
OverlayModal and floating layer surfaces 3
FeedbackStatus, empty, progress, and loading placeholder patterns 6
UtilityGeneral-purpose interface utilities 7

API reference

The default surface is tng-date-range-picker. When you need custom markup, use createDateRangePickerController(...), bindTngDateRangePicker(...), and the date range picker 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-date-range-picker (component)

Wrapper attachment

html
<tng-date-range-picker
  calendarLayout="dual"
  [defaultValue]="{ start: '2024-04-22', end: '2024-04-26' }"
  [minDate]="'2024-04-01'"
  [maxDate]="'2026-03-31'"
  ariaLabel="Invoice period"
></tng-date-range-picker>

Selection and value

PropertyTypeDefaultDetails
defaultValueTngDateRangePickerSelectionInput<TDate> | undefinedundefinedSets the uncontrolled initial range or partial start date.
valueTngDateRangePickerSelectionInput<TDate> | undefinedundefinedControls the committed range from the outside.
enableRangeSelectionbooleantrueKeeps the second click as the range end instead of treating each date as a new start.
minDate / maxDateTngDateInputValue<TDate> | undefinedundefinedDisables out-of-range days, months, and years.
disableDate((date: TDate) => boolean) | nullnullDisables individual dates inside the otherwise valid range.
todayTngDateInputValue<TDate> | undefinedundefinedOverrides which date is marked as today in the grid.

Interaction and behavior

PropertyTypeDefaultDetails
allowManualInputbooleantrueAllows typing directly into the field and committing valid values.
autoCommitViewbooleanfalseControls whether the wrapper should auto-commit when drilling between year, month, and day views.
closeOnEscapebooleantrueCloses the popup when Escape is pressed.
enableTypeaheadbooleantrueEnables keyboard typeahead navigation in month and year grids.
fixedWeeksbooleantrueAlways renders 6 weeks in the day grid to keep the overlay height stable across months.
onPartialInputCommitbooleanfalseAllows partial manual input commits (start date only) before the end date is entered.
skipDisabledbooleantrueControls whether keyboard arrow navigation jumps over disabled dates.
closeOnOutsideClickbooleantrueDismisses the popup when pointer or focus moves outside.
closeOnSelectbooleantrueCloses after a committed range selection.
closeOthersOnOpenbooleanfalseAsks other registered date range pickers to close when this one opens.
restoreFocusbooleantrueRestores focus to the trigger after the popup closes.
showOutsideDaysbooleantrueKeeps adjacent-month days visible in day view.
trapFocusbooleantrueKeeps focus inside the popup while it is open.
weekStartsOnTngWeekdayIndex0Overrides the locale-derived start of week.

Overlay and layout

PropertyTypeDefaultDetails
calendarLayout'single' | 'dual' | 'responsive''single'Single keeps Material-style sequential range selection. Dual fixes the leading calendar to start and the trailing calendar to end; responsive only changes the number of visible panels.
defaultOpenbooleanfalseSets the uncontrolled initial open state.
openboolean | undefinedundefinedControls the popup state from the outside.
placement'auto' | 'bottom' | 'top''auto'Auto-flips the popup when needed. The popup uses logical end alignment against the complete input and trigger shell.
scrollStrategy'block' | 'close' | 'reposition''reposition'Repositions with page scroll and closes if the field leaves view. Use block to lock scrolling while preserving the document scrollbar.
overlayRuntimeTngOverlayRuntime | null | undefinedInternal runtimeLets advanced apps share an overlay layer registry across surfaces.
overlayMinSizenumber | undefinedLayout-awareOverrides the layout-aware minimum popup width before the available viewport width is applied.
overlaySizenumber | undefinedLayout-awareOverrides the layout-aware maximum popup width. Between the bounds, the popup follows the input-shell width.
yearPageSizenumber24Controls how many years are shown per year page.
direction'ltr' | 'rtl''ltr'Flips navigation semantics and keyboard movement for RTL flows.

Accessibility and presentation

PropertyTypeDefaultDetails
adapterTngDateAdapter<TDate> | undefinedDefault date adapterControls parsing, formatting, and visible month or period labels.
ariaDescribedBystring | nullnullForwards an external description id to the host.
ariaLabelstring | nullnullSets a root accessible name when no visible label is present.
ariaLabelledBystring | nullnullPoints the host at an external labeling element.
disabledbooleanfalseDisables the field, trigger, and all calendar interaction.
fullWidthbooleantrueMakes the host fill the available inline size.
idstring | nullnullSeeds the generated input id and overlay relationship ids.
inputAriaLabelstring'Date range input'Labels the editable text input itself.
invalidbooleanfalseForces invalid styling in addition to manual input validation state.
localestringAngular LOCALE_IDDrives weekday names, month labels, and adapter locale defaults.
placeholderstring'MM-DD-YYYY - MM-DD-YYYY'Changes the visible hint only. Parsing still comes from the adapter.
readonlybooleanfalseMakes the text field read-only while still allowing popup selection.

Outputs

OutputTypeDetails
valueChangeTngDateRangePickerValue<TDate>Emits after a click, keyboard commit, or successful manual input range commit.
openChangebooleanEmits whenever the popup opens or closes.
closedTngDateRangePickerCloseReasonReports escape, outside, programmatic, or select close reasons.
activeDateChangeTDateEmits as keyboard focus moves through the calendar model.
previewEndDateChangeTDateEmits as the pointer hovers over candidate end dates during an in-progress range selection.
viewChange'day' | 'month' | 'year'Tracks the current visible panel.
monthChangeTDateEmits when the visible month block changes.
yearChangenumberEmits when the visible year page anchor changes.

Wrapper instance methods

MethodPurpose
clear()Clears the current range selection and returns the wrapper to day view.
close(reason?)Programmatically closes the popup with an optional close reason.
openDateRangePicker()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 { bindTngDateRangePicker, createDateRangePickerController } from '@tailng-ui/primitives';

readonly controller = createDateRangePickerController<Date>({
  ownerDocument: document,
  value: { start: '2024-04-22', end: '2024-04-26' },
  today: '2024-04-18',
  minDate: '2024-04-01',
  maxDate: '2026-03-31',
  closeOnSelect: true,
  calendarLayout: 'dual',
  trapFocus: true,
});

readonly dateRangePicker = bindTngDateRangePicker(this.controller);

Field + overlay wiring

html
<section [tngDateRangePickerHost]="controller">
  <div data-slot="date-range-picker-field">
    <div #anchorShell>
      <div
        data-slot="date-range-picker-input-shell"
        [attr.data-invalid]="dateRangePicker.outputs().validationError !== null ? 'true' : null"
        [attr.data-open]="dateRangePicker.outputs().getTriggerAttributes()['data-open']"
      >
        <input [tngDateRangePickerInput]="controller" type="text" placeholder="MM-DD-YYYY - MM-DD-YYYY" />
        <button [tngDateRangePickerTrigger]="controller" type="button">Open</button>
      </div>

      <section [tngDateRangePickerOverlay]="controller" [tngDateRangePickerOverlayAnchor]="anchorShell">
        <button [tngDateRangePickerPrevButton]="controller" type="button">‹</button>
        <button [tngDateRangePickerPeriodButton]="controller" type="button">
          {{ dateRangePicker.periodLabel() }}
        </button>
        <button [tngDateRangePickerNextButton]="controller" type="button">›</button>

        @for (calendar of dateRangePicker.outputs().calendars; track calendar.index) {
          <div
            [tngDateRangePickerDayGrid]="controller"
            [tngDateRangePickerCalendarIndex]="calendar.index"
          >
            @for (cell of calendar.cells; track cell.id) {
              <button [tngDateRangePickerDayCell]="cell" type="button">{{ cell.label }}</button>
            }
          </div>
        }
      </section>
    </div>
  </div>
</section>
HelperPurpose
bindTngDateRangePicker(controller)Returns signals for outputs() and periodLabel() so Angular templates can stay declarative.
[tngDateRangePickerHost]Applies the public root attributes such as data-open, data-view, and ARIA labels.
[tngDateRangePickerInput] / [tngDateRangePickerTrigger]Forward manual input editing, trigger registration, and wrapper-grade open and keyboard behavior.
[tngDateRangePickerOverlay]Ports the popup to document.body, syncs public overlay attributes, and keeps focus and positioning aligned.
[tngDateRangePickerPrevButton] / [tngDateRangePickerNextButton] / [tngDateRangePickerPeriodButton]Own the standard navigation and drill-down flow without per-view branching in your component.
[tngDateRangePickerDayGrid] / [tngDateRangePickerDayCell]Forward day-grid keyboarding, click handling, hover range behavior, and the public day-cell state hooks.
[tngDateRangePickerMonthGrid] / [tngDateRangePickerMonthOption] / [tngDateRangePickerYearGrid] / [tngDateRangePickerYearOption]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.

OptionTypeDefaultDetails
initialView'day' | 'month' | 'year''day'Starts the controller on a different panel than the wrapper exposes by default.
calendarLayout'single' | 'dual''single'Controls whether outputs.calendars contains one sequential range calendar or a consecutive start/end pair.
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.
onPartialInputCommitbooleanfalseAllows partial manual input commits in advanced headless flows.
preserveViewOnOpenClosebooleantrueKeeps the current panel when reopening instead of always returning to day view.
skipDisabledbooleantrueControls whether keyboard movement jumps across disabled dates.

Controller methods

MethodPurpose
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.