Skip to content

Instantly share code, notes, and snippets.

@baharalidurrani
Created October 13, 2025 11:39
Show Gist options
  • Select an option

  • Save baharalidurrani/a38eec9de4e3b474b2f5dabdcd5aad5c to your computer and use it in GitHub Desktop.

Select an option

Save baharalidurrani/a38eec9de4e3b474b2f5dabdcd5aad5c to your computer and use it in GitHub Desktop.
Mui Free Date Range Picker
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Popover from '@mui/material/Popover';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker';
import dayjs, { type Dayjs } from 'dayjs';
import { useState } from 'react';
function displayDate(date: Date | Dayjs | string, template = 'MMM DD, YYYY'): string {
return dayjs(date).format(template);
}
type Props = {
fromDate?: Dayjs;
toDate?: Dayjs;
onAccept: (dateRange: { fromDate: Dayjs | null; toDate: Dayjs | null }) => void;
};
export default function DateRangePicker({ fromDate, toDate, onAccept }: Props) {
console.debug('πŸ”„ DateRangePicker Rendered');
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [value, setValue] = useState<{ fromDate: Dayjs | null; toDate: Dayjs | null }>({
fromDate: fromDate || dayjs().startOf('month'),
toDate: toDate || dayjs(),
});
function clearHandler() {
onAccept({ fromDate: null, toDate: null });
setValue({ fromDate: null, toDate: null });
setAnchorEl(null);
}
function submitHandler() {
onAccept(value);
setAnchorEl(null);
}
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Button
variant="outlined"
color="inherit"
startIcon={<CalendarMonthIcon />}
onClick={(e) => setAnchorEl(e.currentTarget)}
>
{fromDate && toDate ? `${displayDate(fromDate)} β†’ ${displayDate(toDate)}` : 'Select Dates'}
</Button>
<Popover
open={Boolean(anchorEl)}
anchorEl={anchorEl}
onClose={() => setAnchorEl(null)}
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
>
<Grid container>
<Grid size={{ xs: 12, md: 6 }}>
<StaticDatePicker
localeText={{ toolbarTitle: 'Start Date' }}
slotProps={{ actionBar: { actions: [] } }}
sx={{ backgroundColor: 'unset' }}
value={value.fromDate}
maxDate={value.toDate || undefined}
onChange={(newValue) => setValue((p) => ({ ...p, fromDate: newValue }))}
/>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<StaticDatePicker
localeText={{ toolbarTitle: 'End Date' }}
slotProps={{ actionBar: { actions: [] } }}
sx={{ backgroundColor: 'unset' }}
value={value.toDate}
minDate={value.fromDate || undefined}
onChange={(newValue) => setValue((p) => ({ ...p, toDate: newValue }))}
/>
</Grid>
</Grid>
<Grid container sx={{ justifyContent: 'flex-end', alignItems: 'center', pb: 2, pr: 2 }}>
{fromDate && toDate ? (
<Button onClick={clearHandler} color="error">
Clear
</Button>
) : (
<Button onClick={() => setAnchorEl(null)}>Cancel</Button>
)}
<Button onClick={submitHandler}>Apply</Button>
</Grid>
</Popover>
</LocalizationProvider>
);
}
@baharalidurrani
Copy link
Author

Screenshot 2025-10-13 at 16 40 30 Screenshot 2025-10-13 at 16 41 25 Screenshot 2025-10-13 at 16 41 47

@baharalidurrani
Copy link
Author

Free Date Range Picker using StaticDatePicker

Features:

  1. πŸ“† End Date will always be greater than Start Date.
  2. 🌚 Support Light/Dark Theme.
  3. 🧼 Clear Button.
  4. 🎨 Customization using Material UI Slots and Classes.
  5. πŸŽ‰ Free Date Range Picker.

Demo CodeSandbox: https://codesandbox.io/p/sandbox/mui-freedaterange-picker-vs9xsn

@baharalidurrani
Copy link
Author

Toolbar texts can be styled using classes like MuiPickersToolbar-title:

import { datePickerToolbarClasses } from '@mui/x-date-pickers/DatePicker';
import { pickersToolbarClasses } from '@mui/x-date-pickers/internals';

<StaticDatePicker
  localeText={{ toolbarTitle: 'Start Date' }}
  slotProps={{
    actionBar: { actions: [] },
    toolbar: {
      sx: {
        [`& .${datePickerToolbarClasses.title}`]: { fontSize: '1.75rem' },
        [`& .${pickersToolbarClasses.title}`]: { fontSize: '1rem' },
        // '& .MuiPickersToolbar-title': { bgcolor: 'aqua' },
      },
    },
  }}
  sx={{ backgroundColor: 'unset' }}
  value={value.fromDate}
  maxDate={value.toDate || undefined}
  onChange={(newValue) => setValue((p) => ({ ...p, fromDate: newValue }))}
/>

@baharalidurrani
Copy link
Author

Selected days can be highlighted using custom Day slot:

import { PickersDay, type PickersDayProps } from '@mui/x-date-pickers/PickersDay';

function Day(props: PickersDayProps) {
  return (
    <PickersDay
      {...props}
      sx={{
        ...(props.day.diff(value.fromDate) >= 0 &&
          props.day.diff(value.toDate) <= 0 && {
            bgcolor: (t) => t.palette.primary.main,
            color: (t) => t.palette.primary.contrastText,
          }),
      }}
    />
  );
}

<StaticDatePicker
  localeText={{ toolbarTitle: 'Start Date' }}
  slotProps={{ actionBar: { actions: [] } }}
  slots={{ day: Day }}
  sx={{ backgroundColor: 'unset' }}
  value={value.fromDate}
  maxDate={value.toDate || undefined}
  onChange={(newValue) => setValue((p) => ({ ...p, fromDate: newValue }))}
/>

Looks good but a bit confusion for the users.

Screenshot 2025-10-13 at 17 37 52

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment