# Datetime

Use `ui-datetime` when users need one exact appointment or event moment rather than separate date and time fields. It works well for interviews, approvals, bookings, reminders, and any workflow where the final value needs both the day and the time.

## Import
```ts
import { DatetimeComponent } from 'ui';
```

## Basic date and time selection
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, DatetimeComponent } from 'ui';

@Component({
  selector: 'app-datetime-basic-demo',
  standalone: true,
  imports: [FormsModule, ButtonComponent, DatetimeComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;max-width:24rem">
      <ui-datetime
        label="Meeting start"
        placeholder="YYYY-MM-DD HH:mm"
        [(ngModel)]="value"
        [ngModelOptions]="{ standalone: true }"
      />

      <div
        style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
      >
        <ui-button type="button" appearance="subtle" (click)="value = ''">Clear</ui-button>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest)">
          {{ value || 'No date and time selected.' }}
        </span>
      </div>
    </div>
  `,
})
export class DatetimeBasicDemoComponent {
  protected value = '2026-05-12T09:30';
}
```

## Time step and 12h or 24h clock
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatetimeComponent } from 'ui';

@Component({
  selector: 'app-datetime-step-format-demo',
  standalone: true,
  imports: [FormsModule, DatetimeComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem">
      <div
        style="display:grid;grid-template-columns:repeat(auto-fit,minmax(17rem,1fr));gap:1rem;align-items:start"
      >
        <ui-datetime
          label="30 minute steps"
          placeholder="YYYY-MM-DD HH:mm"
          helpText="24 hour picker with half-hour increments."
          [step]="1800"
          [use24HourFormat]="true"
          [(ngModel)]="halfHourValue"
          [ngModelOptions]="{ standalone: true }"
        />

        <ui-datetime
          label="15 minute steps"
          placeholder="YYYY-MM-DD HH:mm"
          helpText="24 hour picker with denser quarter-hour increments."
          [step]="900"
          [use24HourFormat]="true"
          [(ngModel)]="quarterHourValue"
          [ngModelOptions]="{ standalone: true }"
        />

        <ui-datetime
          label="12 hour picker with AM/PM"
          placeholder="YYYY-MM-DD HH:mm"
          helpText="Open the picker to see the 12 hour time list with AM/PM."
          [step]="1800"
          [use24HourFormat]="false"
          [(ngModel)]="twelveHourValue"
          [ngModelOptions]="{ standalone: true }"
        />
      </div>

      <div
        style="display:flex;flex-wrap:wrap;gap:1rem;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
      >
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest)">
          24h example: <strong style="color:var(--color-neutral-foreground1-rest)">16:30</strong>
        </span>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest)">
          12h picker shows the same slot as
          <strong style="color:var(--color-neutral-foreground1-rest)">4:30 PM</strong>
        </span>
      </div>
    </div>
  `,
})
export class DatetimeStepFormatDemoComponent {
  protected halfHourValue = '2026-05-12T09:30';
  protected quarterHourValue = '2026-05-12T13:15';
  protected twelveHourValue = '2026-05-12T16:30';
}
```

## Min and max constraints
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatetimeComponent } from 'ui';

@Component({
  selector: 'app-datetime-constraints-demo',
  standalone: true,
  imports: [FormsModule, DatetimeComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;max-width:24rem">
      <ui-datetime
        label="Booking window"
        placeholder="YYYY-MM-DD HH:mm"
        min="2026-05-12T08:00"
        max="2026-05-12T18:00"
        [step]="1800"
        [(ngModel)]="value"
        [ngModelOptions]="{ standalone: true }"
      />

      <div
        style="display:flex;flex-direction:column;gap:0.375rem;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest);font-size:0.75rem;color:var(--color-neutral-foreground2-rest)"
      >
        <span>Allowed window: 2026-05-12 08:00 to 18:00</span>
        <span>Selected: {{ value || 'None' }}</span>
      </div>
    </div>
  `,
})
export class DatetimeConstraintsDemoComponent {
  protected value = '2026-05-12T10:00';
}
```

## Size and field states
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatetimeComponent } from 'ui';

@Component({
  selector: 'app-datetime-states-demo',
  standalone: true,
  imports: [FormsModule, DatetimeComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(17rem,1fr));gap:1rem;align-items:start"
    >
      <ui-datetime
        label="Small"
        placeholder="YYYY-MM-DD HH:mm"
        size="small"
        [(ngModel)]="smallValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-datetime
        label="Readonly"
        placeholder="YYYY-MM-DD HH:mm"
        [readonly]="true"
        [(ngModel)]="readonlyValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-datetime
        label="Disabled"
        placeholder="YYYY-MM-DD HH:mm"
        [disabled]="true"
        [(ngModel)]="disabledValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-datetime
        label="Required"
        placeholder="YYYY-MM-DD HH:mm"
        helpText="Choose the final review slot."
        [required]="true"
        [(ngModel)]="requiredValue"
        [ngModelOptions]="{ standalone: true }"
      />
    </div>
  `,
})
export class DatetimeStatesDemoComponent {
  protected smallValue = '2026-05-12T09:00';
  protected readonlyValue = '2026-05-14T15:30';
  protected disabledValue = '2026-05-16T11:00';
  protected requiredValue = '';
}
```

## Reactive form integration
```ts
import { Component, computed } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { ButtonComponent, DatetimeComponent, MessageBarComponent } from 'ui';

@Component({
  selector: 'app-datetime-reactive-form-demo',
  standalone: true,
  imports: [ReactiveFormsModule, ButtonComponent, DatetimeComponent, MessageBarComponent],
  template: `
    <div
      style="display:flex;flex-direction:column;gap:1rem;max-width:24rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <div style="display:flex;flex-direction:column;gap:0.25rem">
        <div style="font-size:0.9375rem;font-weight:600">Approval call</div>
        <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
          Datetime usually matters inside a real scheduling flow with validation and submit state.
        </div>
      </div>

      <ui-datetime
        label="Call time"
        placeholder="YYYY-MM-DD HH:mm"
        helpText="Choose the approval call slot."
        [required]="true"
        [formControl]="datetimeControl"
      />

      @if (datetimeControl.invalid && datetimeControl.touched) {
        <ui-message-bar
          title="Date and time required"
          message="Choose the approval slot before continuing."
          variant="warning"
          appearance="subtle"
          [dismissible]="false"
        />
      }

      <div
        style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
      >
        <ui-button type="button" variant="primary" [disabled]="datetimeControl.invalid">
          Save schedule
        </ui-button>
        <ui-button type="button" appearance="subtle" (click)="reset()">Reset</ui-button>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest)">
          {{ summary() }}
        </span>
      </div>
    </div>
  `,
})
export class DatetimeReactiveFormDemoComponent {
  protected readonly datetimeControl = new FormControl<string | null>('2026-05-14T11:00', {
    nonNullable: false,
    validators: [Validators.required],
  });

  protected readonly summary = computed(
    () => this.datetimeControl.value || 'No date and time selected.',
  );

  protected reset(): void {
    this.datetimeControl.reset('2026-05-14T11:00');
  }
}
```

## Scheduling panel composition
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, DatetimeComponent, MessageBarComponent, TagComponent } from 'ui';

@Component({
  selector: 'app-datetime-scheduling-panel-demo',
  standalone: true,
  imports: [FormsModule, ButtonComponent, DatetimeComponent, MessageBarComponent, TagComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr));gap:1rem;align-items:start;max-width:48rem"
    >
      <div
        style="display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-direction:column;gap:0.25rem">
          <div style="font-size:0.9375rem;font-weight:600">Interview scheduling</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Datetime is strongest when users need one precise appointment slot with both date and
            time context.
          </div>
        </div>

        <ui-datetime
          label="Interview slot"
          placeholder="YYYY-MM-DD HH:mm"
          [step]="1800"
          [(ngModel)]="value"
          [ngModelOptions]="{ standalone: true }"
        />

        <ui-message-bar
          title="Timezone note"
          message="Confirm the selected slot with the candidate before sending the final invite."
          variant="info"
          appearance="subtle"
          [dismissible]="false"
        />
      </div>

      <div
        style="display:flex;flex-direction:column;gap:0.875rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-wrap:wrap;gap:0.5rem">
          <ui-tag text="Hiring" appearance="filled" variant="secondary" />
          <ui-tag text="30 minute slot" appearance="subtle" variant="info" />
          <ui-tag text="Ready to confirm" appearance="subtle" variant="success" />
        </div>

        <div style="display:flex;flex-direction:column;gap:0.375rem">
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Selected slot
          </div>
          <div style="font-size:0.9375rem;font-weight:600">{{ value || 'Not selected' }}</div>
        </div>

        <div
          style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
        >
          <ui-button type="button" variant="primary">Send invite</ui-button>
          <ui-button type="button" appearance="subtle" (click)="value = ''">Reset</ui-button>
        </div>
      </div>
    </div>
  `,
})
export class DatetimeSchedulingPanelDemoComponent {
  protected value = '2026-05-15T14:30';
}
```

## Accessibility

### Input and popup behavior
`ui-datetime` behaves like a text field on desktop and can fall back to a native `type="datetime-local"` input on mobile when `useNativeOnMobile` is enabled.

| Mode | Behavior |
| --- | --- |
| desktop text input | exposes `aria-haspopup="dialog"` and `aria-expanded` |
| mobile native datetime input | relies on native platform datetime semantics |
| disabled or readonly | prevents opening or changing the value |

### Keyboard
Keyboard handling follows the shared field and popup model.

| Key | Action |
| --- | --- |
| `Tab` / `Shift+Tab` | moves through the field, calendar controls, and time picker |
| `Enter` / click on trigger actions | opens the combined picker panel on desktop |
| button activation | selects a date, changes panel navigation, or runs footer actions like clear or now |

### Labels and guidance
Use a label that explains the real task, such as interview slot, approval time, or meeting start. If there is a timezone assumption or a narrow booking window, add helper text or nearby status copy so users understand the expected datetime context.
