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.