A lightweight & configurable timepicker directive
The easiest way to add the timepicker component to your app (will be added to the root module)
Basic
<timepicker [(ngModel)]="mytime"></timepicker> <pre class="alert alert-info">Time is: {{mytime}}</pre>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-basic', templateUrl: './basic.html', standalone: false }) export class DemoTimepickerBasicComponent { mytime: Date = new Date(); }
Form
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<ng-container *ngIf="form"> <form [formGroup]="form"> <timepicker [formControlName]="'myControl'"></timepicker> </form> <br> <button class="btn btn-success" (click)="form.get('myControl')?.enable()">Enable Control</button> <button class="btn btn-warning" (click)="form.get('myControl')?.disable()">Disable Control</button> <br><br> <pre class="alert alert-info">Time is: {{ form.get('myControl')?.value }}</pre> </ng-container>
import { Component } from '@angular/core'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-form', templateUrl: './form.html', standalone: false }) export class DemoTimepickerFormComponent { form = new UntypedFormGroup({ myControl: new UntypedFormControl(new Date()) }); }
Meridian
<timepicker [(ngModel)]="mytime" [showMeridian]="ismeridian"></timepicker> <pre class="alert alert-info">Time is: {{mytime}}</pre> <br> <button type="button" class="btn btn-info" (click)="toggleMode()">12H / 24H</button>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-meridian', templateUrl: './meridian.html', standalone: false }) export class DemoTimepickerMeridianComponent { ismeridian = true; mytime: Date = new Date(); toggleMode(): void { this.ismeridian = !this.ismeridian; } }
Custom meridian
Text in meridian labels can be customized by using meridians
input property
<timepicker [(ngModel)]="mytime" [meridians]="meridians"></timepicker> <pre class="alert alert-info">Time is: {{mytime}}</pre>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-custom-meridian', templateUrl: './custom-meridian.html', standalone: false }) export class DemoTimepickerCustomMeridianComponent { mytime: Date = new Date(); meridians = ['AM(Midnight to Noon)', 'PM(Noon to Midnight)']; }
Min - Max
<timepicker [(ngModel)]="myTime" [min]="minTime" [max]="maxTime"></timepicker> <pre class="alert alert-info">Time is: {{myTime}}</pre>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-min-max', templateUrl: './min-max.html', standalone: false }) export class DemoTimepickerMinMaxComponent { myTime: Date = new Date(); minTime: Date = new Date(); maxTime: Date = new Date(); constructor() { this.minTime.setHours(8); this.minTime.setMinutes(0); this.maxTime.setHours(23); this.maxTime.setMinutes(55); } }
Toggle minutes/seconds
: | : | |||||
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
showMinutes: true
showSeconds: true
<timepicker [(ngModel)]="myTime" [showMinutes]="showMin" [showSeconds]="showSec"></timepicker> <pre class="alert alert-info">Time is: {{myTime}}<br>showMinutes: {{showMin}}<br>showSeconds: {{showSec}}</pre> <button class="btn btn-default text-center" (click)="toggleMinutes()"> {{showMin? 'Hide minutes' : 'Show minutes'}} </button> <button class="btn btn-default text-center" (click)="toggleSeconds()"> {{showSec? 'Hide seconds' : 'Show seconds'}} </button>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-seconds', templateUrl: './toggle-minutes-seconds.html', standalone: false }) export class DemoTimepickerToggleMinutesSecondsComponent { myTime: Date = new Date(); showMin = true; showSec = true; toggleMinutes(): void { this.showMin = !this.showMin; } toggleSeconds(): void { this.showSec = !this.showSec; } }
Disabled
<timepicker [(ngModel)]="myTime" [showMeridian]="isMeridian" [disabled]="!isDisabled"></timepicker> <hr> <button type="button" class="btn btn-info" (click)="isDisabled=!isDisabled">Enable / Disable input</button>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-disabled', templateUrl: './disabled.html', standalone: false }) export class DemoTimepickerDisabledComponent { isMeridian = true; isDisabled = true; myTime = new Date(); }
Readonly
<timepicker [(ngModel)]="myTime" [showMeridian]="isMeridian" [readonlyInput]="!readonly"></timepicker> <hr> <button type="button" class="btn btn-info" (click)="readonly=!readonly">Editable / Readonly input</button>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-readonly', templateUrl: './readonly.html', standalone: false }) export class DemoTimepickerReadonlyComponent { isMeridian = false; readonly = true; myTime = new Date(); }
Custom steps
: | : | |||||
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<timepicker [(ngModel)]="mytime" [hourStep]="hstep" [minuteStep]="mstep" [showSeconds]="true" [secondsStep]="sstep"></timepicker> <pre class="alert alert-info">Time is: {{mytime}}</pre> <div class="row"> <div class="col-xs-6 col-6 col-md-3"> Hours step is: <select class="form-control" [(ngModel)]="hstep"> <option *ngFor="let opt of options.hstep" [value]="opt">{{opt}}</option> </select> </div> <div class="col-xs-6 col-6 col-md-3"> Minutes step is: <select class="form-control" [(ngModel)]="mstep"> <option *ngFor="let opt of options.mstep" [value]="opt">{{opt}}</option> </select> </div> <div class="col-xs-6 col-6 col-md-3"> Seconds step is: <select class="form-control" [(ngModel)]="sstep"> <option *ngFor="let opt of options.sstep" [value]="opt">{{opt}}</option> </select> </div> </div>
import { Component } from '@angular/core'; interface IOptions { hstep: number[]; mstep: number[]; sstep: number[]; } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-custom', templateUrl: './custom.html', standalone: false }) export class DemoTimepickerCustomComponent { hstep = 1; mstep = 15; sstep = 10; mytime: Date = new Date(); options: IOptions = { hstep: [1, 2, 3], mstep: [1, 5, 10, 15, 25, 30], sstep: [5, 10, 20, 30] }; }
Custom validation
<p>Illustrates custom validation, you have to select time between 11:00 and 12:59</p> <div class="form-group mb-3"> <timepicker [(ngModel)]="myTime" [formControl]="ctrl" required></timepicker> </div> <pre class="alert" [class.alert-danger]="!ctrl.valid && !ctrl.pristine" [class.alert-success]="(ctrl.valid && !ctrl.pristine) || ctrl.value === null"> Time is: {{myTime}} </pre> <div class="alert alert-danger" *ngIf="ctrl.errors && ctrl.errors['outOfRange']">Invalid time</div>
import { Component } from '@angular/core'; import { AbstractControl, UntypedFormControl } from '@angular/forms'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-custom-validation', templateUrl: './custom-validation.html', standalone: false }) export class DemoTimepickerCustomValidationComponent { myTime?: Date; ctrl = new UntypedFormControl('', (control: AbstractControl) => { const value = control.value; if (!value) { return null; } const hours = value.getHours(); if (hours < 11 || hours > 12) { return { outOfRange: true }; } return null; }); }
Custom validation with isValid event
isValid
event emits true if a value is a valid data.
Enter an invalid data to see error
<timepicker [(ngModel)]="myTime" [showMeridian]="isMeridian" (isValid)="isValid($event)"></timepicker> <hr> <pre class="alert" [class.alert-danger]="!valid" [class.alert-success]="valid"> Time is: {{myTime}} </pre> <div *ngIf="!valid" class="alert alert-danger">Invalid time</div>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-isvalid', templateUrl: './isvalid.html', standalone: false }) export class DemoTimepickerIsValidComponent { isMeridian = true; myTime = new Date(); valid = true; isValid(event: boolean): void { this.valid = event; } }
Dynamic
<timepicker [(ngModel)]="mytime" (ngModelChange)="changed()" (isValid)="isValid = $event"></timepicker> <pre class="alert alert-info">Time is: {{mytime}}</pre> <pre *ngIf="!isValid" class="alert alert-danger">Invalid time format</pre> <button type="button" class="btn btn-primary" (click)="update()">Set to 14:00</button> <button type="button" class="btn btn-danger" (click)="clear()">Clear</button>
import { Component } from '@angular/core'; import { TimepickerConfig } from 'ngx-bootstrap/timepicker'; export function getTimepickerConfig(): TimepickerConfig { return Object.assign(new TimepickerConfig(), { allowEmptyTime: true }); } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-dynamic', templateUrl: './dynamic.html', providers: [{ provide: TimepickerConfig, useFactory: getTimepickerConfig }], standalone: false }) export class DemoTimepickerDynamicComponent { mytime: Date | undefined = new Date(); isValid?: boolean; update(): void { const time = new Date(); time.setHours(14); time.setMinutes(0); this.mytime = time; } changed(): void { console.log(`Time changed to: ${this.mytime}`); } clear(): void { this.mytime = void 0; } }
Mouse wheel
<timepicker [(ngModel)]="myTime" [mousewheel]="allowMouseWheel"></timepicker> <hr> <button type="button" class="btn btn-info section bd-example" (click)="allowMouseWheel = !allowMouseWheel">Enable / Disable mouse wheel</button> <pre class="alert alert-info">Time is: {{myTime}}</pre>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-mousewheel', templateUrl: './mousewheel.html', standalone: false }) export class DemoTimepickerMousewheelComponent { allowMouseWheel = true; myTime = new Date(); }
Empty date
<timepicker [(ngModel)]="myTime" (isValid)="isValid = $event"></timepicker> <hr> <pre class="alert alert-info">Time is: {{myTime}}</pre> <pre *ngIf="!isValid" class="alert alert-danger">Invalid time format</pre> <button type="button" class="btn btn-danger" (click)="clear()">Clear</button>
import { Component } from '@angular/core'; import { TimepickerConfig } from 'ngx-bootstrap/timepicker'; export function getTimepickerConfig(): TimepickerConfig { return Object.assign(new TimepickerConfig(), { allowEmptyTime: true }); } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-empty-date', templateUrl: './empty-date.html', providers: [{ provide: TimepickerConfig, useFactory: getTimepickerConfig }], standalone: false }) export class DemoTimepickerEmptyDateComponent { allowEmptyTime = true; myTime?: Date = new Date(); isValid?: boolean; clear(): void { this.myTime = void 0; } }
Arrow keys
<timepicker [(ngModel)]="myTime" [arrowkeys]="allowArrowKeys"></timepicker> <hr> <button type="button" class="btn btn-info section bd-example" (click)="allowArrowKeys = !allowArrowKeys">Enable / Disable keyboard arrow keys</button> <pre class="alert alert-info">Time is: {{myTime}}</pre>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-arrowkeys', templateUrl: './arrowkeys.html', standalone: false }) export class DemoTimepickerArrowkeysComponent { allowArrowKeys = true; myTime = new Date(); }
Spinners
<timepicker [(ngModel)]="myTime" [showMeridian]="isMeridian" [showSpinners]="showSpinners"></timepicker> <hr> <button type="button" class="btn btn-info" (click)="showSpinners = !showSpinners">Show / Hide spinners</button>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-spinners', templateUrl: './spinners.html', standalone: false }) export class DemoTimepickerSpinnersComponent { isMeridian = false; showSpinners = true; myTime: Date = new Date(); }
Placeholder
<timepicker [hoursPlaceholder]="hoursPlaceholder" [minutesPlaceholder]="minutesPlaceholder" [secondsPlaceholder]="secondsPlaceholder" [showSeconds]="true"></timepicker>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-placeholder', templateUrl: './placeholder.html', standalone: false }) export class DemoTimepickerPlaceholderComponent { hoursPlaceholder = 'hh'; minutesPlaceholder = 'mm'; secondsPlaceholder = 'ss'; }
Configuring defaults
<timepicker [(ngModel)]="mytime"></timepicker> <pre class="alert alert-info">Time is: {{mytime}}</pre>
import { Component } from '@angular/core'; import { TimepickerConfig } from 'ngx-bootstrap/timepicker'; // such override allows to keep some initial values export function getTimepickerConfig(): TimepickerConfig { return Object.assign(new TimepickerConfig(), { hourStep: 2, minuteStep: 10, showMeridian: false, readonlyInput: false, mousewheel: true, showMinutes: true, showSeconds: false, labelHours: 'Hours', labelMinutes: 'Minutes', labelSeconds: 'Seconds' }); } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'demo-timepicker-config', templateUrl: './config.html', providers: [{ provide: TimepickerConfig, useFactory: getTimepickerConfig }], standalone: false }) export class DemoTimepickerConfigComponent { mytime?: string; }
Installation
ng add ngx-bootstrap --component timepicker
### Standalone component usage import { TimepickerModule } from 'ngx-bootstrap/timepicker'; @Component({ standalone: true, imports: [TimepickerModule,...] }) export class AppComponent(){} ### Module usage import { TimepickerModule } from 'ngx-bootstrap/timepicker'; @NgModule({ imports: [TimepickerModule,...] }) export class AppModule(){}
TimepickerConfig
Provides default configuration values for timepicker
Properties
allowEmptyTime | Type: boolean Default value: false if true emptyTime is not marked as invalid |
ariaLabelHours | Type: string Default value: hours hours aria label |
ariaLabelMinutes | Type: string Default value: minutes minutes aria label |
ariaLabelSeconds | Type: string Default value: seconds seconds aria label |
arrowkeys | Type: boolean Default value: true if true the values of hours and minutes can be changed using the up/down arrow keys on the keyboard |
disabled | Type: boolean Default value: false if true hours and minutes fields will be disabled |
hoursPlaceholder | Type: string Default value: HH placeholder for hours field in timepicker |
hourStep | Type: number Default value: 1 hours change step |
max | Type: Date maximum time user can select |
meridians | Type: string[] meridian labels based on locale |
min | Type: Date minimum time user can select |
minutesPlaceholder | Type: string Default value: MM placeholder for minutes field in timepicker |
minuteStep | Type: number Default value: 5 minutes change step |
mousewheel | Type: boolean Default value: true if true scroll inside hours and minutes inputs will change time |
readonlyInput | Type: boolean Default value: false if true hours and minutes fields will be readonly |
secondsPlaceholder | Type: string Default value: SS placeholder for seconds field in timepicker |
secondsStep | Type: number Default value: 10 seconds changes step |
showMeridian | Type: boolean Default value: true if true works in 12H mode and displays AM/PM. If false works in 24H mode and hides AM/PM |
showMinutes | Type: boolean Default value: true show minutes in timepicker |
showSeconds | Type: boolean Default value: false show seconds in timepicker |
showSpinners | Type: boolean Default value: true if true spinner arrows above and below the inputs will be shown |
Form
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
Toggle minutes/seconds
: | : | |||||
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
showMinutes: true
showSeconds: true
Custom steps
: | : | |||||
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)