Using the below code, we can create a customized time picker with dropdown based on the selection
import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import './CustomTimePicker.css'; // Import custom CSS for styling
interface CustomTimePickerProps {
value: number;
onChange: (value: number) => void;
disabled: boolean;
}
const CustomTimePicker: React.FC<CustomTimePickerProps> = ({ value, onChange, disabled }) => {
const [hours, setHours] = useState<number>(0);
const [minutes, setMinutes] = useState<number>(0);
const [showDropdown, setShowDropdown] = useState(false);
const [activeDropdown, setActiveDropdown] = useState<'hours' | 'minutes' | null>(null);
const [dropdownStyle, setDropdownStyle] = useState<React.CSSProperties>({});
const inputRef = useRef<HTMLInputElement>(null);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const totalMinutes = Math.max(0, value);
const h = Math.floor(totalMinutes / 60);
const m = totalMinutes % 60;
setHours(h);
setMinutes(m);
}, [value]);
const handleTimeChange = (h: number, m: number) => {
setHours(h);
setMinutes(m);
onChange(h * 60 + m);
setShowDropdown(false);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const [h, m] = e.target.value.split(':').map(Number);
if (Number.isInteger(h) && Number.isInteger(m)) {
handleTimeChange(h, m);
}
};
const handleBlur = () => {
if (inputRef.current) {
const [h, m] = inputRef.current.value.split(':').map(Number);
if (!Number.isInteger(h) || !Number.isInteger(m)) {
inputRef.current.value = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
}
}
};
const updateDropdownPosition = () => {
if (!dropdownRef.current || !inputRef.current) return;
const inputRect = inputRef.current.getBoundingClientRect();
setDropdownStyle({
top: `${inputRect.bottom + window.scrollY+4}px`,
left: `${inputRect.left + window.scrollX}px`,
width: `${inputRect.width}px`,
});
};
useEffect(() => {
if (showDropdown) {
updateDropdownPosition();
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) &&
inputRef.current &&
!inputRef.current.contains(event.target as Node)
) {
setShowDropdown(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}
}, [showDropdown]);
const handleClick = (event: React.MouseEvent<HTMLInputElement>) => {
if (!disabled) {
const { offsetWidth } = inputRef.current!;
const clickPosition = event.nativeEvent.offsetX;
// Calculate position to determine if clicking on hours or minutes
if (clickPosition < offsetWidth / 2) {
setActiveDropdown('hours');
} else {
setActiveDropdown('minutes');
}
setShowDropdown(!showDropdown);
updateDropdownPosition();
}
};
return (
<div className="custom-time-picker">
<div className="time-picker-input">
<input
type="text"
value={`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`}
ref={inputRef}
onChange={handleInputChange}
onBlur={handleBlur}
onClick={handleClick}
className={`time-picker-display ${disabled ? 'disabled' : ''}`}
readOnly={disabled}
/>
</div>
{showDropdown &&
ReactDOM.createPortal(
<div className="dropdown" style={dropdownStyle} ref={dropdownRef}>
<div className="dropdown-buttons">
<button
className={`dropdown-button ${activeDropdown === 'hours' ? 'active' : ''}`}
onClick={() => setActiveDropdown('hours')}
>
HH
</button>
<button
className={`dropdown-button ${activeDropdown === 'minutes' ? 'active' : ''}`}
onClick={() => setActiveDropdown('minutes')}
>
MM
</button>
</div>
{activeDropdown === 'hours' && (
<div className="dropdown-options">
{Array.from({ length: 24 }, (_, h) => (
<div
key={h}
className={`dropdown-option ${h === hours ? 'selected' : ''}`}
onClick={() => handleTimeChange(h, minutes)}
>
{h.toString().padStart(2, '0')}
</div>
))}
</div>
)}
{activeDropdown === 'minutes' && (
<div className="dropdown-options">
{Array.from({ length: 60 }, (_, m) => (
<div
key={m}
className={`dropdown-option ${m === minutes ? 'selected' : ''}`}
onClick={() => handleTimeChange(hours, m)}
>
{m.toString().padStart(2, '0')}
</div>
))}
</div>
)}
</div>,
document.body
)}
</div>
);
};
export default CustomTimePicker;