Created
October 13, 2025 11:39
-
-
Save baharalidurrani/a38eec9de4e3b474b2f5dabdcd5aad5c to your computer and use it in GitHub Desktop.
Mui Free Date Range Picker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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> | |
| ); | |
| } |
Author
baharalidurrani
commented
Oct 13, 2025
Author
Free Date Range Picker using StaticDatePicker
Features:
- π End Date will always be greater than Start Date.
- π Support Light/Dark Theme.
- π§Ό Clear Button.
- π¨ Customization using Material UI Slots and Classes.
- π Free Date Range Picker.
Demo CodeSandbox: https://codesandbox.io/p/sandbox/mui-freedaterange-picker-vs9xsn
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 }))}
/>
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.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment