Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

878
Views
Material UI DatePicker custom renderInput

I recently started using material-ui in my React + TypeScript project. The code below was written based on the sample code on the official website.

import AdapterDateFns from '@mui/lab/AdapterDateFns';
import DatePicker from '@mui/lab/DatePicker';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import TextField from '@mui/material/TextField';
import React, { useState } from 'react';

const SampleDatePickerOriginal = () => {
  const [date, setDate] = useState<Date>(new Date());

  const onChangeHandler = (_date: Date | null, keyboardInputValue?: string) => {
    if (_date) {
      setDate(_date);
    }
  };
  return (
    <LocalizationProvider dateAdapter={AdapterDateFns}>
      <DatePicker
        onChange={onChangeHandler}
        value={date}
        renderInput={(params) => <TextField {...params} />}
      />
    </LocalizationProvider>
  );
};

export default SampleDatePickerOriginal;

I wanted to use input element instead of TextField in this code. So I referred to material-ui's issue (https://github.com/mui/material-ui-pickers/issues/1751) and wrote the code below.

import AdapterDateFns from '@mui/lab/AdapterDateFns';
import DatePicker from '@mui/lab/DatePicker';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import React, { useState } from 'react';

const SampleDatePickerCustom = () => {
  const [date, setDate] = useState<Date>(new Date());
  const [isOpen, setIsOpen] = useState<boolean>(false);

  const onChangeHandler = (_date: Date | null, keyboardInputValue?: string) => {
    if(_date){
      setDate(_date);
    }
  };

  return (
    <LocalizationProvider dateAdapter={AdapterDateFns}>
      <DatePicker 
        onChange={onChangeHandler}
        onClose={() => {setIsOpen(false);}}
        open={isOpen}
        value={date} 
        renderInput={({
          ref,
          inputProps,
          disabled,
          onChange,
          value,
          ...other
        }) => (
          <div ref={ref}>
            <input
              style={{ display: 'none' }}
              value={date.toISOString()}
              onChange={onChange}
              disabled={disabled}
              {...inputProps}
            />
            <button onClick={() => {setIsOpen(!isOpen);}}>
              OPEN
            </button>
          </div>)} />
    </LocalizationProvider>
  );
};

export default SampleDatePickerCustom;

This code works fine, but the calendar that opens is in the upper left corner. How can I make it appear just below the button like when I use TextField?

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

I was stuck on the same problem here today and luckily got it working for me now.

The idea is that you have to pass an anchor element to the Material UI Popper component, which is basically the wrapper for your Datepicker Popup. That means you have to create a ref object for your custom input and pass that to the popper object as anchorEl. If you check the MaterialUI X documentation for the Datepicker API, you can see it under the Props section as PropperProps.

Your code then would look something like this:

import React, { useState, useRef } from 'react';

const SampleDatePickerCustom = () => {
  const [date, setDate] = useState<Date>(new Date());
  const [isOpen, setIsOpen] = useState<boolean>(false);
  const customInputRef = useRef();

  const onChangeHandler = (_date: Date | null, keyboardInputValue?: string) => {
    if(_date){
      setDate(_date);
    }
  };

  return (
    <LocalizationProvider dateAdapter={AdapterDateFns}>
      <DatePicker 
        onChange={onChangeHandler}
        onClose={() => {setIsOpen(false);}}
        open={isOpen}
        value={date} 
        PopperProps={{ anchorEl: customInputRef.current }}
        renderInput={({
          ref,
          inputProps,
          disabled,
          onChange,
          value,
          ...other
        }) => (
          <div ref={ref}>
            <input
              style={{ display: 'none' }}
              value={date.toISOString()}
              onChange={onChange}
              disabled={disabled}
              ref={customInputRef}
              {...inputProps}
            />
            <button onClick={() => {setIsOpen(!isOpen);}}>
              OPEN
            </button>
          </div>)} />
    </LocalizationProvider>
  );
};

The only things that I added are the customInputRef object, which is assigned as a ref to your input and the PropperProps object on your Datepicker, which only has one property, the customInputRef.current element. That should make the Popper be anchored at the provided custom input element. I didn't type the additions, since I'm not the best at TS, but I hope it's enough to understand how it works :)

about 4 years ago · Juan Pablo Isaza Report

0

I was able to work around it by using TextField but hiding it with styles... <TextField style={{ opacity: 0, width: 0, height: 0 }} {...params} />

<LocalizationProvider dateAdapter={AdapterDateFns}>
   <DatePicker
    open={calendarOpen}
    onClose={() => setCalendarOpen(false)}
    value={date}
    onChange={(newValue) => setDate(newValue)}
    renderInput={(params) => (
      <div>
      {/* HACK: this next line was needed to get the calendar to render in the right position */}
        <TextField style={{ opacity: 0, width: 0, height: 0 }} {...params} /> 
        <Button
          className="p-1"
          variant="outlined"
          onClick={() => setCalendarOpen((calendarOpen) => !calendarOpen)}>
          <CalendarIcon />
        </Button>
      </div>
    )}
  />
</LocalizationProvider>
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!