Search code examples
reactjsmaterial-uitimepicker

Disable manual input for MUI TimePicker


I have a bit of a custom TimePicker provided from Material UI. I add an ability for the user to select only whole hours, such as 15:00, 16:00 etc. by clicking on a clock icon

What I want to achieve is to add same for manual input of the text field. For now user can manually add any valid time, for example 14:34, which is incorrect for my case

Can anyone help me?

Here is my TimePicker:

<LocalizationProvider dateAdapter={AdapterDateFns} locale={locale}>
    <TimePicker
        ampm={false}
        openTo="hours"
        views={['hours']}
        inputFormat="HH:mm"
        mask="__:__"
        value={dayStartValue}
        InputAdornmentProps={{
            position: 'start',
        }}
        components={{
            OpenPickerIcon: ClockFilledIcon,
        }}
        onChange={(newValue) => {
            setDayStartValue(newValue)
        }}
        renderInput={(params) =>
            <TextField
                {...params}
                helperText="Input start of Day time"
            />
            
        }
    />
</LocalizationProvider>

Solution

  • You can control and validate the user's input when he clicks away from the time picker by using onBlur inside InputProps.

    import * as React from "react";
    import TextField from "@mui/material/TextField";
    import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
    import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
    import { TimePicker } from "@mui/x-date-pickers/TimePicker";
    
    export default function BasicTimePicker() {
      const [dayStartValue, setDayStartValue] = React.useState<Date | null>(null);
    
      return (
        <LocalizationProvider
          dateAdapter={AdapterDateFns}
          locale={locale}
        >
          <TimePicker
            ampm={false}
            openTo="hours"
            views={["hours"]}
            inputFormat="HH:mm"
            mask="__:__"
            value={dayStartValue}
            InputAdornmentProps={{
              position: "start"
            }}
            components={{
                OpenPickerIcon: ClockFilledIcon,
            }}
            onChange={(newValue: Date, keyboardInputValue?: string) => {
              setDayStartValue(newValue);
            }}
            renderInput={(params) => (
              <TextField {...params} helperText="Input start of Day time" />
            )}
            InputProps={{
              onBlur: (
                e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement, Element>
              ) => {
                const newDate = new Date(dayStartValue);
                newDate.setMinutes(0);
                if (e.target.value && e.target.value.length === 5) {
                  setDayStartValue(newDate);
                }
              }
            }}
          />
        </LocalizationProvider>
      );
    }
    

    For the validation we check the user input and if it's a valid Date (5 characters length), we create a new Date with that and set the minutes to 0.

    Code Sandbox example