Primitives
A date picker is a component that allows users to select a date from a calendar and navigate through months and years.
November 2025
S M T W T F S import { Component, computed, signal } from "@angular/core";
import { NgIcon, provideIcons } from "@ng-icons/core";
import {
heroChevronLeftMini,
heroChevronRightMini,
} from "@ng-icons/heroicons/mini";
import {
NgpDatePicker,
NgpDatePickerCell,
NgpDatePickerCellRender,
NgpDatePickerDateButton,
NgpDatePickerGrid,
NgpDatePickerLabel,
NgpDatePickerNextMonth,
NgpDatePickerPreviousMonth,
NgpDatePickerRowRender,
} from "ng-primitives/date-picker";
@Component({
selector: "app-date-picker",
imports: [
NgIcon,
NgpDatePicker,
NgpDatePickerLabel,
NgpDatePickerNextMonth,
NgpDatePickerPreviousMonth,
NgpDatePickerGrid,
NgpDatePickerCell,
NgpDatePickerRowRender,
NgpDatePickerCellRender,
NgpDatePickerDateButton,
],
providers: [provideIcons({ heroChevronRightMini, heroChevronLeftMini })],
template: `
<div
[(ngpDatePickerDate)]="date"
[(ngpDatePickerFocusedDate)]="focused"
ngpDatePicker
>
<div class="date-picker-header">
<button ngpDatePickerPreviousMonth aria-label="previous month">
<ng-icon name="heroChevronLeftMini" />
</button>
<h2 ngpDatePickerLabel>{{ label() }}</h2>
<button ngpDatePickerNextMonth aria-label="next month">
<ng-icon name="heroChevronRightMini" />
</button>
</div>
<table ngpDatePickerGrid>
<thead>
<tr>
<th scope="col" abbr="Sunday">S</th>
<th scope="col" abbr="Monday">M</th>
<th scope="col" abbr="Tuesday">T</th>
<th scope="col" abbr="Wednesday">W</th>
<th scope="col" abbr="Thursday">T</th>
<th scope="col" abbr="Friday">F</th>
<th scope="col" abbr="Saturday">S</th>
</tr>
</thead>
<tbody>
<tr *ngpDatePickerRowRender>
<td *ngpDatePickerCellRender="let date" ngpDatePickerCell>
<button ngpDatePickerDateButton>{{ date.getDate() }}</button>
</td>
</tr>
</tbody>
</table>
</div>
`,
styles: `
[ngpDatePicker] {
display: inline-block;
background-color: var(--ngp-background);
border-radius: 12px;
padding: 16px;
box-shadow: var(--ngp-shadow);
border: 1px solid var(--ngp-border);
}
.date-picker-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 36px;
margin-bottom: 16px;
}
th {
font-size: 14px;
font-weight: 500;
width: 40px;
height: 40px;
text-align: center;
color: var(--ngp-text-secondary);
}
[ngpDatePickerLabel] {
font-size: 14px;
font-weight: 500;
color: var(--ngp-text-primary);
}
[ngpDatePickerPreviousMonth],
[ngpDatePickerNextMonth] {
all: unset;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
font-size: 20px;
border: 1px solid var(--ngp-border);
cursor: pointer;
}
[ngpDatePickerPreviousMonth][data-hover],
[ngpDatePickerNextMonth][data-hover] {
background-color: var(--ngp-background-hover);
}
[ngpDatePickerPreviousMonth][data-focus-visible],
[ngpDatePickerNextMonth][data-focus-visible] {
outline: 2px solid var(--ngp-focus-ring);
}
[ngpDatePickerPreviousMonth][data-press],
[ngpDatePickerNextMonth][data-press] {
background-color: var(--ngp-background-active);
}
[ngpDatePickerPreviousMonth][data-disabled],
[ngpDatePickerNextMonth][data-disabled] {
cursor: not-allowed;
color: var(--ngp-text-disabled);
}
[ngpDatePickerDateButton] {
all: unset;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
}
[ngpDatePickerDateButton][data-today] {
color: var(--ngp-text-blue);
}
[ngpDatePickerDateButton][data-hover] {
background-color: var(--ngp-background-hover);
}
[ngpDatePickerDateButton][data-focus-visible] {
outline: 2px solid var(--ngp-focus-ring);
outline-offset: 2px;
}
[ngpDatePickerDateButton][data-press] {
background-color: var(--ngp-background-active);
}
[ngpDatePickerDateButton][data-outside-month] {
color: var(--ngp-text-disabled);
}
[ngpDatePickerDateButton][data-selected] {
background-color: var(--ngp-background-inverse);
color: var(--ngp-text-inverse);
}
[ngpDatePickerDateButton][data-selected][data-outside-month] {
background-color: var(--ngp-background-disabled);
color: var(--ngp-text-disabled);
}
[ngpDatePickerDateButton][data-disabled] {
cursor: not-allowed;
color: var(--ngp-text-disabled);
}
`,
})
export default class DatePickerExample {
/**
* The selected date.
*/
readonly date = signal<Date>(new Date());
/**
* Store the current focused date.
*/
readonly focused = signal<Date>(new Date());
/**
* Get the current focused date in string format.
* @returns The focused date in "February 2024" format.
*/
readonly label = computed(
() =>
`${this.focused().toLocaleString("default", { month: "long" })} ${this.focused().getFullYear()}`,
);
}
Import the DatePicker primitives from ng-primitives/date-picker.
import {
NgpDatePicker,
NgpDateRangePicker,
NgpDatePickerLabel,
NgpDatePickerNextMonth,
NgpDatePickerPreviousMonth,
NgpDatePickerGrid,
NgpDatePickerCell,
NgpDatePickerRowRender,
NgpDatePickerCellRender,
NgpDatePickerDateButton,
} from 'ng-primitives/date-picker';
Assemble the date-picker directives in your template.
<div ngpDatePicker>
<div>
<button ngpDatePickerPreviousMonth>...</button>
<h2 ngpDatePickerLabel>...</h2>
<button ngpDatePickerNextMonth>...</button>
</div>
<table ngpDatePickerGrid>
<thead>
<tr>
<th scope="col" abbr="Sunday">S</th>
...
</tr>
</thead>
<tbody>
<tr *ngpDatePickerRowRender>
<td *ngpDatePickerCellRender="let date" ngpDatePickerCell>
<button ngpDatePickerDateButton>...</button>
</td>
</tr>
</tbody>
</table>
</div>
Create a reusable component that uses the date picker directives.
import { Component } from '@angular/core';
import { DatePicker } from './date-picker';
@Component({
selector: 'app-root',
imports: [DatePicker],
template: `
<app-date-picker />
`,
})
export default class App {}
Generate a reusable date-picker component using the Angular CLI.
ng g ng-primitives:primitive date-picker
path: The path at which to create the component file.prefix: The prefix to apply to the generated component selector.componentSuffix: The suffix to apply to the generated component class name.fileSuffix: The suffix to apply to the generated component file name. Defaults to component.exampleStyles: Whether to include example styles in the generated component file. Defaults to true.Here are some additional examples of how to use the Date Picker primitives.
The date range picker allows users to select a range of dates by selecting the start and end dates.
August 2025
S M T W T F S import { Component, computed, signal } from "@angular/core";
import { NgIcon, provideIcons } from "@ng-icons/core";
import {
heroChevronLeftMini,
heroChevronRightMini,
} from "@ng-icons/heroicons/mini";
import {
NgpDatePickerCell,
NgpDatePickerCellRender,
NgpDatePickerDateButton,
NgpDatePickerGrid,
NgpDatePickerLabel,
NgpDatePickerNextMonth,
NgpDatePickerPreviousMonth,
NgpDatePickerRowRender,
NgpDateRangePicker,
} from "ng-primitives/date-picker";
@Component({
selector: "app-date-range-picker",
imports: [
NgIcon,
NgpDateRangePicker,
NgpDatePickerLabel,
NgpDatePickerNextMonth,
NgpDatePickerPreviousMonth,
NgpDatePickerGrid,
NgpDatePickerCell,
NgpDatePickerRowRender,
NgpDatePickerCellRender,
NgpDatePickerDateButton,
],
providers: [provideIcons({ heroChevronRightMini, heroChevronLeftMini })],
template: `
<div
[(ngpDateRangePickerStartDate)]="startDate"
[(ngpDateRangePickerEndDate)]="endDate"
[(ngpDateRangePickerFocusedDate)]="focused"
ngpDateRangePicker
>
<div class="date-picker-header">
<button ngpDatePickerPreviousMonth aria-label="previous month">
<ng-icon name="heroChevronLeftMini" />
</button>
<h2 ngpDatePickerLabel>{{ label() }}</h2>
<button ngpDatePickerNextMonth aria-label="next month">
<ng-icon name="heroChevronRightMini" />
</button>
</div>
<table ngpDatePickerGrid>
<thead>
<tr>
<th scope="col" abbr="Sunday">S</th>
<th scope="col" abbr="Monday">M</th>
<th scope="col" abbr="Tuesday">T</th>
<th scope="col" abbr="Wednesday">W</th>
<th scope="col" abbr="Thursday">T</th>
<th scope="col" abbr="Friday">F</th>
<th scope="col" abbr="Saturday">S</th>
</tr>
</thead>
<tbody>
<tr *ngpDatePickerRowRender>
<td *ngpDatePickerCellRender="let date" ngpDatePickerCell>
<button ngpDatePickerDateButton>{{ date.getDate() }}</button>
</td>
</tr>
</tbody>
</table>
</div>
`,
styles: `
[ngpDateRangePicker] {
display: inline-block;
background-color: var(--ngp-background);
border-radius: 12px;
padding: 16px;
box-shadow: var(--ngp-shadow);
border: 1px solid var(--ngp-border);
}
.date-picker-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 36px;
margin-bottom: 16px;
}
th {
font-size: 14px;
font-weight: 500;
width: 40px;
height: 40px;
text-align: center;
color: var(--ngp-text-secondary);
}
[ngpDatePickerLabel] {
font-size: 14px;
font-weight: 500;
color: var(--ngp-text-primary);
}
[ngpDatePickerPreviousMonth],
[ngpDatePickerNextMonth] {
all: unset;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
font-size: 20px;
border: 1px solid var(--ngp-border);
cursor: pointer;
}
[ngpDatePickerPreviousMonth][data-hover],
[ngpDatePickerNextMonth][data-hover] {
background-color: var(--ngp-background-hover);
}
[ngpDatePickerPreviousMonth][data-focus-visible],
[ngpDatePickerNextMonth][data-focus-visible] {
outline: 2px solid var(--ngp-focus-ring);
}
[ngpDatePickerPreviousMonth][data-press],
[ngpDatePickerNextMonth][data-press] {
background-color: var(--ngp-background-active);
}
[ngpDatePickerPreviousMonth][data-disabled],
[ngpDatePickerNextMonth][data-disabled] {
cursor: not-allowed;
color: var(--ngp-text-disabled);
}
[ngpDatePickerCell] {
padding: 0;
}
[ngpDatePickerDateButton] {
all: unset;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
}
[ngpDatePickerDateButton][data-today] {
color: var(--ngp-text-blue);
}
[ngpDatePickerDateButton][data-hover] {
background: var(--ngp-background-hover);
}
[ngpDatePickerDateButton][data-focus-visible] {
outline: 2px solid var(--ngp-focus-ring);
outline-offset: 2px;
}
[ngpDatePickerDateButton][data-press] {
background: var(--ngp-background-active);
}
[ngpDatePickerDateButton][data-outside-month] {
color: var(--ngp-text-disabled);
}
[ngpDatePickerDateButton][data-selected] {
background: var(--ngp-background-inverse);
color: var(--ngp-text-inverse);
}
[ngpDatePickerDateButton][data-selected]:not([data-range-end]) {
border-radius: 8px 0 0 8px;
}
[ngpDatePickerDateButton][data-selected][data-range-end] {
border-radius: 0 8px 8px 0;
}
[ngpDatePickerDateButton][data-selected][data-range-start][data-range-end] {
border-radius: 8px;
}
[ngpDatePickerDateButton][data-range-between] {
background: color-mix(
in srgb,
var(--ngp-background-inverse) 5%,
transparent
);
border-radius: 0;
}
[ngpDatePickerDateButton][data-selected][data-outside-month] {
background-color: var(--ngp-background-disabled);
color: var(--ngp-text-disabled);
}
[ngpDatePickerDateButton][data-disabled] {
cursor: not-allowed;
color: var(--ngp-text-disabled);
}
`,
})
export default class DateRangePickerExample {
/**
* The start date of the range.
*/
readonly startDate = signal<Date>(new Date(2025, 7, 10));
/**
* The end date of the range.
*/
readonly endDate = signal<Date>(new Date(2025, 7, 14));
/**
* Store the current focused date.
*/
readonly focused = signal<Date>(new Date(2025, 7, 10));
/**
* Get the current focused date in string format.
* @returns The focused date in "February 2024" format.
*/
readonly label = computed(
() =>
`${this.focused().toLocaleString("default", { month: "long" })} ${this.focused().getFullYear()}`,
);
}
By default, the date picker uses the native JavaScript Date object, however the date picker is designed to work with any date library. To use a date library, such as Luxon, you need to specify the appropriate date adapter. The date adapter is an abstraction layer that allows components to use date objects from any date library, ensuring compatibility and easy integration. To learn more about the date adapter, see the Date Adapter documentation.
The following directives are available to import from the ng-primitives/date-picker package:
The outermost container for the date picker. The minimum date that can be selected.
The maximum date that can be selected.
Determine if the date picker is disabled.
A function that is called to determine if a specific date should be disabled.
Sets which day starts the week in the calendar.
Accepts 0-7 where 1=Monday, 2=Tuesday, 3=Wednesday, 4=Thursday, 5=Friday, 6=Saturday, 7=Sunday.
Defaults to NgpDatePickerConfig.firstDayOfWeek (default 7 if not overridden).
Note: Update calendar header column order when changing from Sunday start.
The selected value.
The focused value.
Emit when the date changes.
Emit when the focused date changes.
[ngpDatePicker]ngpDatePicker
The following data attributes are available on the ngpDatePicker directive:
| Attribute | Description |
|---|---|
data-disabled |
Applied when the date picker is disabled. |
The minimum date that can be selected.
The maximum date that can be selected.
Determine if the date picker is disabled.
A function that is called to determine if a specific date should be disabled.
Sets which day starts the week in the calendar.
Accepts 0-7 where 1=Monday, 2=Tuesday, 3=Wednesday, 4=Thursday, 5=Friday, 6=Saturday, 7=Sunday.
Defaults to NgpDatePickerConfig.firstDayOfWeek (default 7 if not overridden).
Note: Update calendar header column order when changing from Sunday start.
The selected start date
The selected end date
The focused value.
Emit when the date changes.
Emit when the end date changes.
Emit when the focused date changes.
[ngpDateRangePicker]ngpDateRangePicker
The following data attributes are available on the ngpDateRangePicker directive:
| Attribute | Description |
|---|---|
data-disabled |
Applied when the date range picker is disabled. |
The label that displays the current month and year typically in the header of the date picker. This will be announced by screen readers when the date changes. Define the aria live attribute.
[ngpDatePickerLabel]ngpDatePickerLabel
The following data attributes are available on the ngpDatePickerLabel directive:
| Attribute | Description |
|---|---|
data-disabled |
Applied when the date picker is disabled. |
A button that navigates to the previous month.[ngpDatePickerPreviousMonth]ngpDatePickerPreviousMonth
The following data attributes are available on the ngpDatePickerPreviousMonth directive:
| Attribute | Description |
|---|---|
data-hover |
Applied when the button is hovered. |
data-focus-visible |
Applied when the button is focused. |
data-press |
Applied when the button is pressed. |
data-disabled |
Applied when the button is disabled. |
A button that navigates to the next month.[ngpDatePickerNextMonth]ngpDatePickerNextMonth
The following data attributes are available on the ngpDatePickerNextMonth directive:
| Attribute | Description |
|---|---|
data-hover |
Applied when the button is hovered. |
data-focus-visible |
Applied when the button is focused. |
data-press |
Applied when the button is pressed. |
data-disabled |
Applied when the button is disabled. |
The grid that contains the days of the month.[ngpDatePickerGrid]ngpDatePickerGrid
The following data attributes are available on the ngpDatePickerGrid directive:
| Attribute | Description |
|---|---|
data-disabled |
Applied when the date picker is disabled. |
A structural directive that renders a row of weekdays in the date picker grid.[ngpDatePickerRowRender]ngpDatePickerRowRender
A structural directive that renders a cell in the date picker grid.
*ngpDatePickerCellRenderngpDatePickerCellRenderThe following context fields are available on the ngpDatePickerCellRender directive:
The date value for the cell.
A cell in the date picker grid.[ngpDatePickerCell]ngpDatePickerCell
The following data attributes are available on the ngpDatePickerCell directive:
| Attribute | Description |
|---|---|
data-disabled |
Applied when the cell is disabled. |
data-selected |
Applied when the cell is selected. |
A button that represents a date in the date picker grid.[ngpDatePickerDateButton]ngpDatePickerDateButton
The following data attributes are available on the ngpDatePickerDateButton directive:
| Attribute | Description |
|---|---|
data-selected |
Applied when the button is selected. |
data-outside-month |
Applied when the button is outside the current month. |
data-today |
Applied when the button represents the current date. |
data-hover |
Applied when the button is hovered. |
data-focus-visible |
Applied when the button is focused. |
data-press |
Applied when the button is pressed. |
data-disabled |
Applied when the button is disabled. |
data-range-start |
Applied when the button is the start of a date range. |
data-range-end |
Applied when the button is the end of a date range. |
data-range-between |
Applied when the button is between the start and end of a date range. |
Adheres to the WAI-ARIA design pattern.
You can configure the default options for all NgpDatePicker and NgpDateRangePicker calendars in your application by using the provideDatePickerConfig function in a providers array.
import { provideDatePickerConfig } from 'ng-primitives/date-picker';
bootstrapApplication(AppComponent, {
providers: [
provideDatePickerConfig({
firstDayOfWeek: 1, // Monday
}),
],
});
Sets which day starts the week in date picker and date range picker calendars.
Accepts 1-7 where:
1=Monday,2=Tuesday,3=Wednesday,4=Thursday,5=Friday,6=Saturday,7=Sunday (default).1 (Monday), while US applications typically use
7 (Sunday).
Copyright © 2025 Angular Primitives