Timepicker component on github

A lightweight & configurable timepicker directive

The easiest way to add the timepicker component to your app (will be added to the root module)

Basic

#

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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

#

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

<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

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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

#

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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)
Hours step is:
Minutes step is:
Seconds step is:
<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

#

Illustrates custom validation, you have to select time between 11:00 and 12:59

      
 :    
      
  Time is: 
<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

      
 :    
      

  Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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

#

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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

#

      
 :    
      

Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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

#

      
 :    
      

Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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

#

      
 :    
      

Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
<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

#

   
 : 
   
Time is: 
<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(){}

Selector

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

Basic

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Form

      
 :    
      



Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Meridian

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Custom meridian

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Min - Max

      
 :    
      
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

Disabled

      
 :    
      

Readonly

   
 : 
   

Custom steps

       
 :  :    
       
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)
Hours step is:
Minutes step is:
Seconds step is:

Custom validation

Illustrates custom validation, you have to select time between 11:00 and 12:59

      
 :    
      
  Time is: 

Custom validation with isValid event

      
 :    
      

  Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Dynamic

      
 :    
      
Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Mouse wheel

      
 :    
      

Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Empty date

      
 :    
      

Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Arrow keys

      
 :    
      

Time is: Mon Jul 28 2025 17:41:28 GMT+0300 (Eastern European Summer Time)

Spinners

   
 : 
   

Placeholder

       
 :  :    
       

Configuring defaults

   
 : 
   
Time is: