Skip to content

softwarity/timezone-select

Repository files navigation

Softwarity

@softwarity/timezone-select

npm version license

An Angular Material timezone selector component with UTC offset navigation. Browse timezones by offset using arrow buttons, then select a specific timezone from the filtered dropdown.

Live Demo

Timezone-select Preview

Features

  • UTC Offset Navigation - Browse timezones by offset with < +00:00 > arrows (infinite loop)
  • Browser Timezone Detection - Optional button to auto-detect and set browser timezone
  • IANA Timezone Names - Uses native Intl.supportedValuesOf('timeZone') for timezone data
  • MatFormField Compatible - Implements MatFormFieldControl for seamless integration
  • Signal-first - value is a model() signal: [(value)] two-way binding, and Signal Forms' [formField] drives it natively (FormValueControl contract)
  • Material 3 Ready - Uses M3 design tokens for theming
  • Standalone Component - Easy to import in any Angular 21+ application
  • No Dependencies - Uses native JavaScript Intl API for timezone data

Installation

npm install @softwarity/timezone-select

Peer Dependencies

Package Version
@angular/common >= 21.0.0
@angular/core >= 21.0.0
@angular/cdk >= 21.0.0
@angular/forms >= 21.0.0
@angular/material >= 21.0.0

Usage

Import the component in your Angular component:

import { signal } from '@angular/core';
import { TimezoneSelectComponent } from '@softwarity/timezone-select';
import { MatFormFieldModule } from '@angular/material/form-field';

@Component({
  selector: 'app-my-component',
  imports: [TimezoneSelectComponent, MatFormFieldModule],
  template: `
    <mat-form-field appearance="outline">
      <mat-label>Timezone</mat-label>
      <timezone-select [(value)]="timezone" />
      <mat-hint>Select your preferred timezone</mat-hint>
    </mat-form-field>
  `
})
export class MyComponent {
  timezone = signal<string | null>('Europe/Paris');
}

Migrating from 1.x: the ControlValueAccessor was removed (Angular forbids implementing it alongside the Signal Forms FormValueControl contract), so [formControl]/ngModel no longer bind. Use [(value)] (or [value] + (valueChange)), or Signal Forms' [formField].

API

Selector

timezone-select

Inputs

Input Type Default Description
value model<string | null> null The selected timezone — two-way bindable with [(value)], driven by [formField] in Signal Forms
placeholder string '' Placeholder text
required boolean false Whether the field is required
disabled boolean false Whether the field is disabled
showDetectButton boolean false Shows a button to detect and set browser timezone

Outputs

Output Type Description
valueChange string | null Emits when the selected timezone changes (implicit output of the value model)
touch void Emits when focus leaves the control — enables Signal Forms' debounce('blur')

Value

The component value is an IANA timezone name string (e.g., 'Europe/Paris', 'America/New_York', 'UTC').

Theming (Material 3)

The component provides a SCSS mixin for theming. Import and use it in your styles.scss:

@use '@angular/material' as mat;
@use '@softwarity/timezone-select/timezone-select-theme' as timezone-select;

html {
  @include mat.theme((color: (primary: mat.$violet-palette)));

  // Apply timezone-select theme
  @include timezone-select.theme();
}

Examples

Basic Usage

import { signal } from '@angular/core';
import { TimezoneSelectComponent } from '@softwarity/timezone-select';

@Component({
  imports: [TimezoneSelectComponent, MatFormFieldModule],
  template: `
    <mat-form-field>
      <mat-label>Timezone</mat-label>
      <timezone-select [(value)]="timezone" />
    </mat-form-field>
  `
})
export class MyComponent {
  timezone = signal<string | null>('UTC');
}

With Value Change Handler

@Component({
  template: `
    <mat-form-field>
      <mat-label>Timezone</mat-label>
      <timezone-select
        [value]="timezone()"
        (valueChange)="onTimezoneChange($event)" />
    </mat-form-field>
  `
})
export class MyComponent {
  timezone = signal<string | null>('America/New_York');

  onTimezoneChange(timezone: string | null): void {
    this.timezone.set(timezone);
    console.log('Selected timezone:', timezone);
  }
}

Signal Forms

import { signal } from '@angular/core';
import { form, FormField } from '@angular/forms/signals';

@Component({
  imports: [TimezoneSelectComponent, MatFormFieldModule, FormField],
  template: `
    <mat-form-field>
      <mat-label>Timezone</mat-label>
      <timezone-select [formField]="settingsForm.timezone" />
    </mat-form-field>
  `
})
export class MyComponent {
  settingsModel = signal({ timezone: 'Europe/London' });
  settingsForm = form(this.settingsModel);
}

Disabled State

@Component({
  template: `
    <mat-form-field>
      <mat-label>Timezone</mat-label>
      <timezone-select [value]="'Europe/London'" [disabled]="true" />
    </mat-form-field>
  `
})
export class MyComponent {}

Timezone Data

The component uses the native JavaScript Intl API to:

  • Get the list of supported timezones: Intl.supportedValuesOf('timeZone')
  • Calculate UTC offsets: Intl.DateTimeFormat with timeZoneName: 'shortOffset'

This ensures the timezone data is always up-to-date with the browser's IANA timezone database.

License

Apache-2.0