Skip to content

Pending Review

Pending Review from User Experience (UX)

Time Component

Overview

The PWC Time component provides an interactive time input interface with support for 12-hour format, AM/PM selection, and both manual input and dropdown picker functionality. Built with comprehensive keyboard navigation, validation features, and accessibility support, it enables precise time selection through multiple input methods including direct typing, arrow key navigation, and visual picker interface.

Core Capabilities

  • 12-Hour Format Input - Native 12-hour time format with separate hour, minute, and AM/PM fields for intuitive time entry
  • Dual Input Methods - Support for both direct keyboard input and visual dropdown picker with hour/minute selection lists
  • Advanced Keyboard Navigation - Arrow key navigation between fields, increment/decrement controls, and smart field focusing
  • Input Validation - Real-time validation with range checking (1-12 hours, 0-59 minutes) and automatic formatting
  • Visual Time Picker - Dropdown interface with scrollable hour, minute, and AM/PM selection lists for precise time selection
  • Form Integration - Seamless PWC form context integration with validation states, error handling, and Date value management

When to use Time:

  • Form fields requiring precise time input for scheduling, appointments, deadlines, and time-sensitive data collection
  • Settings interfaces where users need to configure time-based parameters, preferences, or system schedules
  • Data entry forms requiring standardized time format input with validation and user-friendly selection methods
  • Scheduling applications where users need to select specific times with both typing and visual selection options

When not to use Time:

  • Date selection scenarios where full date/time pickers provide better user experience and integrated functionality
  • Duration input where time span components or numeric inputs are more appropriate for representing time periods
  • Simple time display scenarios where read-only time formatting components provide better visual presentation

Basic Implementation

import { PwcTime } from "@progress-i360/pwc-react";

function TimeInput() {
  return (
    <PwcTime
      label="Appointment Time"
      name="appointmentTime"
      required
    />
  );
}
import { useEffect, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/time';

type TimeElement = HTMLElement & {
  value?: Date;
  required?: boolean;
  disabled?: boolean;
};

function ScheduleTime() {
  const timeRef = useRef<TimeElement | null>(null);
  const [selectedTime, setSelectedTime] = useState<Date | undefined>();

  useEffect(() => {
    const timeElement = timeRef.current;
    if (!timeElement) {
      return;
    }

    const handleChange = (event: Event) => {
      const detail = (event as CustomEvent<Date | undefined>).detail;
      setSelectedTime(detail);
    };

    timeElement.addEventListener('pwc-change', handleChange);
    return () => {
      timeElement.removeEventListener('pwc-change', handleChange);
    };
  }, []);

  useEffect(() => {
    const timeElement = timeRef.current;
    if (!timeElement) {
      return;
    }

    timeElement.value = selectedTime;
  }, [selectedTime]);

  return (
    <pwc-time
      ref={timeRef}
      label="Meeting Time"
      name="meetingTime"
      hint="Select your meeting time"
    ></pwc-time>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/time";

@Component({
  selector: 'time-demo',
  template: `
    <pwc-time 
      label="Meeting Start Time" 
      name="meetingStart"
      [value]="meetingStart"
      required
      hint="When does the meeting begin?"
      (pwc-change)="updateMeetingStart($event)">
    </pwc-time>

    <pwc-time 
      label="Meeting End Time" 
      name="meetingEnd"
      [value]="meetingEnd"
      [disabled]="!meetingStart"
      hint="When does the meeting end?"
      (pwc-change)="updateMeetingEnd($event)">
    </pwc-time>

    <pwc-time 
      label="Reminder Time" 
      name="reminderTime"
      [value]="reminderTime"
      hint="When should you be reminded?"
      (pwc-change)="updateReminder($event)">
    </pwc-time>

    <pwc-time 
      label="Daily Standup" 
      name="standupTime"
      [value]="standupTime"
      required
      hint="Daily team meeting time"
      (pwc-change)="updateStandup($event)">
    </pwc-time>

    <div class="time-summary" *ngIf="hasScheduledTimes">
      <p>Meeting: {{ formatTimeRange() }}</p>
      <p>Duration: {{ getMeetingDuration() }} minutes</p>
      <p>Standup: {{ formatTime(standupTime) }}</p>
    </div>

    <div class="quick-actions" *ngIf="hasValidMeeting">
      <pwc-button 
        label="Set Reminder" 
        variant="outline"
        (pwc-click)="setDefaultReminder()">
      </pwc-button>

      <pwc-button 
        label="Save Schedule" 
        variant="primary"
        (pwc-click)="saveSchedule()">
      </pwc-button>
    </div>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class TimeDemo {
  meetingStart?: Date;
  meetingEnd?: Date;
  reminderTime?: Date;
  standupTime = new Date(2024, 0, 1, 9, 0); // Default 9:00 AM

  get hasScheduledTimes() {
    return this.meetingStart || this.standupTime;
  }

  get hasValidMeeting() {
    return this.meetingStart && this.meetingEnd;
  }

  updateMeetingStart(event: CustomEvent<Date | undefined>) {
    this.meetingStart = event.detail;

    // Auto-set end time 1 hour later
    if (this.meetingStart && !this.meetingEnd) {
      const endTime = new Date(this.meetingStart);
      endTime.setHours(endTime.getHours() + 1);
      this.meetingEnd = endTime;
    }

    // Auto-set reminder 15 minutes before
    if (this.meetingStart) {
      const reminderTime = new Date(this.meetingStart);
      reminderTime.setMinutes(reminderTime.getMinutes() - 15);
      this.reminderTime = reminderTime;
    }
  }

  updateMeetingEnd(event: CustomEvent<Date | undefined>) {
    this.meetingEnd = event.detail;
  }

  updateReminder(event: CustomEvent<Date | undefined>) {
    this.reminderTime = event.detail;
  }

  updateStandup(event: CustomEvent<Date | undefined>) {
    this.standupTime = event.detail ?? this.standupTime;
  }

  formatTime(date?: Date): string {
    if (!date) return 'Not set';
    return date.toLocaleTimeString([], { 
      hour: 'numeric', 
      minute: '2-digit',
      hour12: true 
    });
  }

  formatTimeRange(): string {
    if (!this.meetingStart) return 'Not scheduled';
    const start = this.formatTime(this.meetingStart);
    const end = this.meetingEnd ? this.formatTime(this.meetingEnd) : 'TBD';
    return `${start} - ${end}`;
  }

  getMeetingDuration(): number {
    if (!this.meetingStart || !this.meetingEnd) return 0;
    const diffMs = this.meetingEnd.getTime() - this.meetingStart.getTime();
    return Math.round(diffMs / (1000 * 60)); // Convert to minutes
  }

  setDefaultReminder() {
    if (this.meetingStart) {
      const reminderTime = new Date(this.meetingStart);
      reminderTime.setMinutes(reminderTime.getMinutes() - 15);
      this.reminderTime = reminderTime;
    }
  }

  saveSchedule() {
    const schedule = {
      meetingStart: this.meetingStart,
      meetingEnd: this.meetingEnd,
      reminderTime: this.reminderTime,
      standupTime: this.standupTime,
      duration: this.getMeetingDuration()
    };

    console.log('Saving schedule:', schedule);

    // Simulate API call
    setTimeout(() => {
      alert(`Schedule saved! Meeting: ${this.formatTimeRange()}, Duration: ${this.getMeetingDuration()} minutes`);
    }, 500);
  }
}
// Create a simple time input with hour, minute, and AM/PM fields
function createTimeInput() {
  const container = document.createElement('div');
  container.style.padding = '20px';
  container.style.maxWidth = '300px';

  // Label
  const label = document.createElement('label');
  label.textContent = 'Meeting Time:';
  label.style.display = 'block';
  label.style.marginBottom = '8px';
  label.style.fontWeight = 'bold';

  // Time input container
  const timeContainer = document.createElement('div');
  timeContainer.style.display = 'flex';
  timeContainer.style.alignItems = 'center';
  timeContainer.style.gap = '8px';
  timeContainer.style.border = '1px solid #ccc';
  timeContainer.style.borderRadius = '4px';
  timeContainer.style.padding = '8px';

  // Hour input
  const hourInput = document.createElement('input');
  hourInput.type = 'number';
  hourInput.min = '1';
  hourInput.max = '12';
  hourInput.placeholder = 'HH';
  hourInput.style.width = '40px';
  hourInput.style.border = 'none';
  hourInput.style.textAlign = 'center';

  // Colon separator
  const colon = document.createElement('span');
  colon.textContent = ':';
  colon.style.fontWeight = 'bold';

  // Minute input
  const minuteInput = document.createElement('input');
  minuteInput.type = 'number';
  minuteInput.min = '0';
  minuteInput.max = '59';
  minuteInput.placeholder = 'MM';
  minuteInput.style.width = '40px';
  minuteInput.style.border = 'none';
  minuteInput.style.textAlign = 'center';

  // AM/PM select
  const ampmSelect = document.createElement('select');
  ampmSelect.style.border = 'none';
  ampmSelect.style.marginLeft = '4px';

  const amOption = document.createElement('option');
  amOption.value = 'AM';
  amOption.textContent = 'AM';

  const pmOption = document.createElement('option');
  pmOption.value = 'PM';
  pmOption.textContent = 'PM';

  ampmSelect.appendChild(amOption);
  ampmSelect.appendChild(pmOption);

  // Auto-format and navigation
  hourInput.addEventListener('input', () => {
    if (hourInput.value.length === 2) {
      minuteInput.focus(); // Move to next field
    }
  });

  minuteInput.addEventListener('input', () => {
    // Pad with zero if needed
    if (minuteInput.value.length === 1 && parseInt(minuteInput.value) > 5) {
      ampmSelect.focus();
    } else if (minuteInput.value.length === 2) {
      ampmSelect.focus();
    }
  });

  // Display current time
  function getCurrentTime() {
    const hour = hourInput.value || '12';
    const minute = (minuteInput.value || '00').padStart(2, '0');
    const ampm = ampmSelect.value;
    return `${hour}:${minute} ${ampm}`;
  }

  // Log time changes
  [hourInput, minuteInput, ampmSelect].forEach(input => {
    input.addEventListener('change', () => {
      console.log('Time selected:', getCurrentTime());
    });
  });

  timeContainer.appendChild(hourInput);
  timeContainer.appendChild(colon);
  timeContainer.appendChild(minuteInput);
  timeContainer.appendChild(ampmSelect);

  container.appendChild(label);
  container.appendChild(timeContainer);
  document.body.appendChild(container);
}

createTimeInput();

Usage Patterns

  • Appointment Scheduling - Time selection for meetings, consultations, and scheduled events with precise timing requirements
  • Configuration Settings - System time preferences, notification schedules, and automated task timing configuration
  • Form Time Fields - Structured data entry requiring time input with validation and user-friendly selection interfaces
  • Schedule Management - Daily schedules, work hours, break times, and recurring time-based configurations

Best Practices

Content Strategy Guidelines

  • Clear Time Context - Use descriptive labels that clearly indicate the purpose and context of the time selection requirement
  • Appropriate Default Values - Set sensible default times that match user expectations and common use patterns for the specific context
  • Helpful Guidance - Provide hint text that explains time format expectations, selection methods, and any relevant constraints or requirements
  • Validation Messaging - Use clear, actionable error messages that guide users toward valid time input and selection

Performance Optimization

  • Efficient Event Handling - Use debounced change handlers and optimized event management to prevent excessive updates during user interaction
  • Keyboard Navigation Optimization - Implement smooth transitions between fields and efficient arrow key handling for rapid time entry
  • Picker Performance - Optimize dropdown rendering and positioning calculations for smooth user experience across different devices
  • Memory Management - Properly handle Date object creation and component cleanup to prevent memory leaks in time-intensive applications

Integration Architecture

  • Form Context Coordination - Integrate seamlessly with PWC form systems for validation, error handling, and Date value synchronization
  • Date Object Management - Handle Date object creation, manipulation, and serialization consistently across different use cases and time zones
  • Validation Strategy Design - Implement comprehensive time validation patterns that handle edge cases and user input variations effectively
  • Accessibility Standards - Ensure proper ARIA labeling, keyboard navigation, and screen reader compatibility for inclusive time selection experiences

Common Use Cases

Data Table Headers

  • Event scheduling interfaces with start times, end times, and duration calculations for calendar and booking systems
  • Employee time tracking with clock-in, clock-out, and break time recording for payroll and attendance management
  • System configuration panels with maintenance windows, backup schedules, and automated task timing settings

Search Result Sections

  • Appointment booking systems with available time slot selection and scheduling conflict detection
  • Meeting room reservation interfaces with time-based availability filtering and scheduling optimization
  • Service booking platforms with time slot selection and duration-based pricing calculations

Dashboard Widget Headers

  • Notification settings with custom alert times and reminder scheduling for user preference management
  • Report generation interfaces with scheduled report timing and delivery time configuration options
  • System monitoring dashboards with time-based alert thresholds and maintenance window scheduling

Troubleshooting

Common Issues

Actions Not Triggering

Symptoms: Time picker doesn't open, keyboard navigation doesn't work, or input values don't update properly

Solutions:

  • Verify that event handlers are properly bound and component instance references are maintained for picker functionality

  • Check that keyboard event handling works correctly for arrow keys, field navigation, and increment/decrement operations

  • Ensure that Date object creation and manipulation functions work properly across different time formats and edge cases

Actions Not Visible

Symptoms: Time picker dropdown doesn't appear, input fields don't render, or time icon doesn't display properly

Solutions:

  • Confirm that dropdown positioning calculations work correctly and picker appears in the correct location relative to input

  • Check that time icon renders properly with appropriate color theming and click functionality for picker activation

  • Verify that input field layout and styling accommodate hour, minute, and AM/PM sections properly with correct spacing

Layout Issues

Symptoms: Input fields appear misaligned, picker dropdown appears in wrong position, or component doesn't fit form layouts

Solutions:

  • Use appropriate container styling and responsive design patterns to ensure component fits within form layouts properly

  • Check that dropdown positioning with Floating UI works correctly across different screen sizes and scroll positions

  • Ensure that input field widths and spacing accommodate different time formats and font sizes without layout disruption

Icon Problems

Symptoms: Time icon doesn't display, picker icon doesn't respond to clicks, or icon colors don't match theme properly

Solutions:

  • Verify that time icon is available in your icon system and renders correctly with appropriate sizing and color theming

  • Check that icon click handlers trigger picker functionality properly without interfering with input field focus management

  • Ensure that icon disabled states work correctly and provide appropriate visual feedback based on component state

Implementation Support

  • Time Format Handling - Best practices for 12-hour format management, AM/PM logic, and Date object manipulation patterns
  • Keyboard Navigation Strategies - Comprehensive guidance for field navigation, increment/decrement controls, and accessibility optimization
  • Form Integration Patterns - Integration strategies with PWC form systems, validation workflows, and time-based data management

Resources

Storybook Documentation

For comprehensive API documentation, interactive examples, and testing tools: 📖 View Complete API Documentation in Storybook →


This guide provides high-level implementation guidance. For detailed API specifications and interactive examples, visit our Storybook documentation.