# Time Picker

Use `ui-time-picker` when you need the time selection primitive directly, outside of the shared field wrapper. It works well in drawers, scheduling panels, compact operational rows, and custom overlays where a full `ui-time` field would add unnecessary chrome.

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

## Basic wheel selection
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TimePickerComponent } from 'ui';

@Component({
  selector: 'app-time-picker-basic-demo',
  standalone: true,
  imports: [FormsModule, TimePickerComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:26rem;">
      <ui-time-picker
        [value]="selectedTime"
        [showLabel]="true"
        label="Start time"
        [step]="900"
        [use24HourFormat]="true"
        (timeChange)="selectedTime = $event"
      />

      <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)"
      >
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest);">
          Selected value:
          <strong style="color:var(--color-neutral-foreground1-rest)">{{
            selectedTime || 'Not set'
          }}</strong>
        </span>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest);">
          Wheel interactions emit normalized <strong>HH:mm</strong> strings.
        </span>
      </div>
    </div>
  `,
})
export class TimePickerBasicDemoComponent {
  protected selectedTime = '09:30';
}
```

## Minute step and 12h or 24h format
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TimePickerComponent } from 'ui';

@Component({
  selector: 'app-time-picker-format-step-demo',
  standalone: true,
  imports: [FormsModule, TimePickerComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;">
      <div
        style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;align-items:start"
      >
        <ui-time-picker
          [value]="quarterHourValue"
          [showLabel]="true"
          label="15 minute cadence"
          [step]="900"
          [use24HourFormat]="true"
          (timeChange)="quarterHourValue = $event"
        />

        <ui-time-picker
          [value]="halfHourValue"
          [showLabel]="true"
          label="30 minute cadence"
          [step]="1800"
          [use24HourFormat]="true"
          (timeChange)="halfHourValue = $event"
        />

        <ui-time-picker
          [value]="twelveHourValue"
          [showLabel]="true"
          label="12 hour with AM or PM"
          [step]="1800"
          [use24HourFormat]="false"
          (timeChange)="twelveHourValue = $event"
        />
      </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 storage stays normalized:
          <strong style="color:var(--color-neutral-foreground1-rest)">16:30</strong>
        </span>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest);">
          In 12h mode the same value is presented as
          <strong style="color:var(--color-neutral-foreground1-rest)">4:30 PM</strong>
        </span>
      </div>
    </div>
  `,
})
export class TimePickerFormatStepDemoComponent {
  protected quarterHourValue = '09:15';
  protected halfHourValue = '13:30';
  protected twelveHourValue = '16:30';
}
```

## Size and inline layout
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TimePickerComponent } from 'ui';

@Component({
  selector: 'app-time-picker-size-layout-demo',
  standalone: true,
  imports: [FormsModule, TimePickerComponent],
  template: `
    <div style="display:grid;gap:1rem;width:100%;">
      <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));gap:1rem;">
        <div style="display:grid;gap:0.75rem;">
          <span
            style="font-size:0.8125rem;font-weight:600;color:var(--color-neutral-foreground2-rest);"
            >Small</span
          >
          <ui-time-picker
            [value]="smallValue"
            size="small"
            [step]="900"
            [use24HourFormat]="true"
            (timeChange)="smallValue = $event"
          />
        </div>

        <div style="display:grid;gap:0.75rem;">
          <span
            style="font-size:0.8125rem;font-weight:600;color:var(--color-neutral-foreground2-rest);"
            >Medium</span
          >
          <ui-time-picker
            [value]="mediumValue"
            size="medium"
            [step]="900"
            [use24HourFormat]="true"
            (timeChange)="mediumValue = $event"
          />
        </div>

        <div style="display:grid;gap:0.75rem;">
          <span
            style="font-size:0.8125rem;font-weight:600;color:var(--color-neutral-foreground2-rest);"
            >Large</span
          >
          <ui-time-picker
            [value]="largeValue"
            size="large"
            [step]="900"
            [use24HourFormat]="true"
            (timeChange)="largeValue = $event"
          />
        </div>
      </div>

      <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;">
        <div style="display:grid;gap:0.75rem;">
          <span
            style="font-size:0.8125rem;font-weight:600;color:var(--color-neutral-foreground2-rest);"
            >Inline without label</span
          >
          <ui-time-picker
            [value]="inlineValue"
            [inline]="true"
            [step]="1800"
            [use24HourFormat]="true"
            (timeChange)="inlineValue = $event"
          />
        </div>

        <div style="display:grid;gap:0.75rem;">
          <span
            style="font-size:0.8125rem;font-weight:600;color:var(--color-neutral-foreground2-rest);"
            >Inline with visible label</span
          >
          <ui-time-picker
            [value]="inlineLabelValue"
            [inline]="true"
            [showLabel]="true"
            label="Review slot"
            [step]="1800"
            [use24HourFormat]="true"
            (timeChange)="inlineLabelValue = $event"
          />
        </div>
      </div>
    </div>
  `,
})
export class TimePickerSizeLayoutDemoComponent {
  protected smallValue = '08:30';
  protected mediumValue = '11:00';
  protected largeValue = '15:30';
  protected inlineValue = '10:00';
  protected inlineLabelValue = '14:30';
}
```

## Disabled and preset states
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, TimePickerComponent } from 'ui';

@Component({
  selector: 'app-time-picker-states-demo',
  standalone: true,
  imports: [FormsModule, ButtonComponent, TimePickerComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;">
      <div
        style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;align-items:start"
      >
        <ui-time-picker
          [value]="activeValue"
          [showLabel]="true"
          label="Active picker"
          [step]="900"
          [use24HourFormat]="true"
          (timeChange)="activeValue = $event"
        />

        <ui-time-picker
          [value]="'09:30'"
          [showLabel]="true"
          label="Disabled picker"
          [step]="900"
          [use24HourFormat]="true"
          [disabled]="true"
        />

        <ui-time-picker
          [value]="amPmValue"
          [showLabel]="true"
          label="Disabled 12 hour picker"
          [step]="1800"
          [use24HourFormat]="false"
          [disabled]="disabledTwelveHour"
          (timeChange)="amPmValue = $event"
        />
      </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 variant="secondary" appearance="outline" (click)="toggleDisabled12h()">
          {{ disabledTwelveHour ? 'Enable' : 'Disable' }} 12h picker
        </ui-button>
        <ui-button variant="secondary" appearance="outline" (click)="reset()">Reset</ui-button>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest);">
          Active value:
          <strong style="color:var(--color-neutral-foreground1-rest)">{{ activeValue }}</strong>
        </span>
      </div>
    </div>
  `,
})
export class TimePickerStatesDemoComponent {
  protected activeValue = '13:15';
  protected amPmValue = '16:30';
  protected disabledTwelveHour = true;

  protected toggleDisabled12h(): void {
    this.disabledTwelveHour = !this.disabledTwelveHour;
  }

  protected reset(): void {
    this.activeValue = '13:15';
    this.amPmValue = '16:30';
    this.disabledTwelveHour = true;
  }
}
```

## Inline schedule row
```ts
import { Component } from '@angular/core';
import { ButtonComponent, CardComponent, TimePickerComponent } from 'ui';

@Component({
  selector: 'app-time-picker-inline-schedule-demo',
  standalone: true,
  imports: [ButtonComponent, CardComponent, TimePickerComponent],
  template: `
    <ui-card appearance="outline" borderStyle="dashed" ariaLabel="Support handoff row">
      <div uiCardHeader style="display:grid;gap:0.25rem;">
        <strong style="font-size:0.9375rem;">Support handoff</strong>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground3-rest);">
          Inline time pickers work well in compact operational rows where users tweak one slot fast.
        </span>
      </div>

      <div
        uiCardBody
        style="display:flex;flex-wrap:wrap;gap:1rem 1.25rem;align-items:end;justify-content:space-between"
      >
        <div style="display:flex;flex-wrap:wrap;gap:1rem 1.25rem;align-items:end;">
          <ui-time-picker
            [value]="startValue"
            [inline]="true"
            [showLabel]="true"
            label="Starts"
            [step]="1800"
            [use24HourFormat]="true"
            (timeChange)="startValue = $event"
          />

          <ui-time-picker
            [value]="endValue"
            [inline]="true"
            [showLabel]="true"
            label="Ends"
            [step]="1800"
            [use24HourFormat]="true"
            (timeChange)="endValue = $event"
          />
        </div>

        <div style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;">
          <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest);">
            Current span:
            <strong style="color:var(--color-neutral-foreground1-rest)"
              >{{ startValue }} - {{ endValue }}</strong
            >
          </span>
          <ui-button variant="secondary" appearance="outline" (click)="reset()">Reset</ui-button>
        </div>
      </div>
    </ui-card>
  `,
})
export class TimePickerInlineScheduleDemoComponent {
  protected startValue = '09:00';
  protected endValue = '17:00';

  protected reset(): void {
    this.startValue = '09:00';
    this.endValue = '17:00';
  }
}
```

## Scheduling panel composition
```ts
import { Component } from '@angular/core';
import { ButtonComponent, CardComponent, MessageBarComponent, TimePickerComponent } from 'ui';

@Component({
  selector: 'app-time-picker-scheduling-panel-demo',
  standalone: true,
  imports: [ButtonComponent, CardComponent, MessageBarComponent, TimePickerComponent],
  template: `
    <ui-card appearance="filled-alternative" ariaLabel="Interview scheduling panel">
      <div
        uiCardPreview
        style="min-height:7rem;background:linear-gradient(135deg,#dfe9fb 0%,#c8d9f4 100%)"
      ></div>

      <div uiCardHeader style="display:grid;gap:0.25rem;">
        <strong style="font-size:1rem;line-height:1.35;">Candidate review session</strong>
        <span style="font-size:0.8125rem;color:var(--color-neutral-foreground3-rest);">
          Choose a focused slot for the panel and keep timezone-sensitive handoff details nearby.
        </span>
      </div>

      <div uiCardBody style="display:grid;gap:1rem;">
        <ui-message-bar
          title="Panel availability"
          description="All reviewers are free between 13:00 and 18:00 CET."
          variant="info"
          appearance="subtle"
          size="small"
        />

        <div
          style="display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem;align-items:start"
        >
          <ui-time-picker
            [value]="reviewTime"
            [showLabel]="true"
            label="Interview starts"
            [step]="1800"
            [use24HourFormat]="false"
            (timeChange)="reviewTime = $event"
          />

          <ui-time-picker
            [value]="debriefTime"
            [showLabel]="true"
            label="Debrief starts"
            [step]="1800"
            [use24HourFormat]="false"
            (timeChange)="debriefTime = $event"
          />
        </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)"
        >
          <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest);">
            Candidate review:
            <strong style="color:var(--color-neutral-foreground1-rest)">{{ reviewTime }}</strong>
          </span>
          <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest);">
            Debrief:
            <strong style="color:var(--color-neutral-foreground1-rest)">{{ debriefTime }}</strong>
          </span>
        </div>
      </div>

      <div uiCardFooter style="display:flex;flex-wrap:wrap;gap:0.75rem;">
        <ui-button variant="primary" appearance="filled">Confirm slot</ui-button>
        <ui-button variant="secondary" appearance="outline" (click)="reset()">Reset</ui-button>
      </div>
    </ui-card>
  `,
})
export class TimePickerSchedulingPanelDemoComponent {
  protected reviewTime = '14:00';
  protected debriefTime = '16:30';

  protected reset(): void {
    this.reviewTime = '14:00';
    this.debriefTime = '16:30';
  }
}
```

## Accessibility

### Wheel and option semantics
`ui-time-picker` renders separate hour and minute listboxes with option buttons, plus an AM or PM radio group in 12 hour mode.

| Part | Semantics |
| --- | --- |
| hour wheel | `role="listbox"` with option buttons |
| minute wheel | `role="listbox"` with option buttons |
| 12 hour selector | radio button group for `AM` or `PM` |
| disabled state | wheels and meridiem controls become non-interactive |

### Keyboard
Keyboard support follows the wheel interaction model.

| Key | Action |
| --- | --- |
| `Tab` / `Shift+Tab` | moves between hour wheel, minute wheel, and AM or PM group when present |
| `ArrowUp` / `ArrowDown` | moves by one option in the focused wheel |
| `PageUp` / `PageDown` | jumps by larger increments in the focused wheel |
| click or button activation | selects a visible option from the wheel |

### Labels and context
Because this component is often embedded directly into custom panels, give it surrounding context. Use `showLabel` and `label` when the picker stands on its own, or place it near explicit section text so screen reader users understand whether the slot controls a start time, end time, handoff, or deadline.
