Picker
This page describes how people can use picker with Material UI and how they can build custom pickers.
Usage in a Popover
Without Material UI
With Base UI Popover.*
components
The user can use the Picker.*
components in combination with the Popover.*
components from @base-ui-components/react
to build a picker:
import { Popover } from '@base-ui-components/react/popover';
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
function DesktopDatePicker(props) {
const manager = useDateManager();
return (
<Picker.Root manager={manager} {...props}>
{({ open, setOpen }) => (
<Popover.Root open={open} onOpenChange={setOpen}>
<PickerField.Root>
{/** See field documentation */}
<Popover.Trigger>📅</Popover.Trigger>
</PickerField.Root>
<Popover.Backdrop />
<Popover.Positioner>
<Popover.Popup>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Popover.Popup>
</Popover.Positioner>
</Popover.Root>
)}
</Picker.Root>
);
}
<DesktopDatePicker value={value} onChange={setValue} />;
With React Aria <Popover />
components
Even if Base UI will be the solution presented in the doc to connect the field and the view, nothing prevents the user from using another library:
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { Dialog, DialogTrigger, Button, Popover } from 'react-aria-components';
function DesktopDatePicker(props) {
const manager = useDateManager();
return (
<Picker.Root manager={manager} {...props}>
{({ open, setOpen }) => (
<DialogTrigger isOpen={open} onOpenChange={setOpen}>
<PickerField.Root>
{/** See field documentation */}
<Button>📅</Button>
</PickerField.Root>
<Popover>
<Dialog>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Dialog>
</Popover>
</DialogTrigger>
)}
</Picker.Root>
);
}
<DesktopDatePicker value={value} onChange={setValue} />;
With Material UI
The user can use the <DesktopDatePicker />
component:
import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';
<DesktopDatePicker value={value} onChange={setValue} />;
Usage in a Dialog
Without Material UI
With Base UI Dialog.*
components
The user can use the Picker.*
components in combination with the Dialog.*
components from @base-ui-components/react
to build a picker:
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { Dialog } from '@base-ui-components/react/dialog';
function MobileDatePicker(props) {
const manager = useDateManager();
return (
<Picker.Root manager={manager} {...props}>
{({ open, setOpen }) => (
<Dialog.Root open={open} onOpenChange={setOpen}>
<PickerField.Root>
{/** See field documentation */}
<Dialog.Trigger>📅</Dialog.Trigger>
</PickerField.Root>
<Dialog.Backdrop />
<Dialog.Popup>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Dialog.Popup>
</Dialog.Root>
)}
</Picker.Root>
);
}
<MobileDatePicker value={value} onChange={setValue} />;
With Mantine <Modal />
component
The user can use a Modal that expect different props for its lifecycle:
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { Modal, Button } from '@mantine/core';
function MobileDatePicker(props) {
const manager = useDateManager();
return (
<Picker.Root manager={manager} {...props}>
{({ open, openPicker, closePicker }) => (
<DialogTrigger isOpen={open} onClose={closePicker}>
<PickerField.Root>
{/** See field documentation */}
<Button onClick={openPicker}>📅</Button>
</PickerField.Root>
<Popover>
<Dialog>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Dialog>
</Popover>
</DialogTrigger>
)}
</Picker.Root>
);
}
<MobileDatePicker value={value} onChange={setValue} />;
With Material UI
import { MobileDatePicker } from '@mui/x-date-pickers/MobileDatePicker';
<MobileDatePicker value={value} onChange={setValue} />;
Responsive usage
Without Material UI
If the library does not provide any higher level utilities to create a responsive picker and sticks with "1 React component = 1 DOM element", here is what a responsive picker could look like:
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { useMediaQuery } from '@base-ui-components/react-utils/useMediaQuery'; // not sure how the util package will be named
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { Popover } from '@base-ui-components/react/popover';picker
) : (
<Dialog.Trigger>📅</Dialog.Trigger>
)}
</PickerField.Root>
);
const view = <Calendar.Root>{/** See calendar documentation */}</Calendar.Root>;
if (isDesktop) {
return (
<Picker.Root manager={manager} {...props}>
{({ open, setOpen }) => (
<Popover.Root open={open} onOpenChange={setOpen}>
{field}
<Popover.Backdrop />
<Popover.Positioner>
<Popover.Popup>{view}</Popover.Popup>
</Popover.Positioner>
</Popover.Root>
)}
</Picker.Root>
);
}
return (
<Picker.Root manager={manager} {...props}>
{({ open, setOpen }) => (
<Dialog.Root open={open} onOpenChange={setOpen}>
{field}
<Dialog.Backdrop />
<Dialog.Popup>{view}</Dialog.Popup>
</Dialog.Root>
)}
</Picker.Root>
);
}
<DatePicker value={value} onChange={setValue}>
With Material UI
The user can use the <DatePicker />
component:
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
<DatePicker value={value} onChange={setValue} />;
Static usage
Without Material UI
The user can use the <Picker.StaticRoot />
component to create a static picker.
Most of the time, the user can use directly components such as Calendar.*
, but the static picker can be useful in the following scenarios:
- several view components are used together (the main use case is to create a Date Time Picker). The static picker will make sure the value is correctly handled between those components.
- the user wants to add UI elements like a shortcut panel using utility components like
<Picker.SetValue />
.
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
function StaticDatePicker(props) {
const manager = useDateManager();
return (
<Picker.StaticRoot manager={manager} {...props}>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Picker.StaticRoot>
);
}
<StaticDatePicker value={value} onChange={setValue} />;
With Material UI
TODO
Usage with date and time
Without Material UI
The user can use both the Calendar.*
and the DigitalClock.*
components together to render the date and the time picking UI side by side:
import { Popover } from '@base-ui-components/react/popover';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar';
import { DigitalClock } from '@base-ui-components/react-x-date-pickers/digital-clock';
<Popover.Popup>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
<DigitalClock.Root>{/** See digital clock documentation */}</DigitalClock.Root>
</Popover.Popup>;
If the user wants to set the UI to select the date, then the time, he can conditionally render the view component based on the active section:
import { Popover } from '@base-ui-components/react/popover';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar';
import { DigitalClock } from '@base-ui-components/react-x-date-pickers/digital-clock';
import { isDateSection } from '@base-ui-components/react-x-date-pickers/utils';
<Popover.Popup>
<Picker.ContextValue>
{({ activeSection }) =>
isDateSection(activeSection) ? (
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
) : (
<DigitalClock.Root>
{/** See digital clock documentation */}
</DigitalClock.Root>
)
}
</Picker.ContextValue>
</Popover.Popup>;
With Material UI
TODO
Add an action bar
Without Material UI
The user can use the <Picker.AcceptValue />
, <Picker.CancelValue />
and <Picker.SetValue />
components to create an action bar and interact with the value:
import { Popover } from '@base-ui-components/react/popover';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
<Popover.Popup>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
<div>
<Picker.SetValue target={null}>Clear</Picker.Clear>
<Picker.SetValue target={dayjs()}>Today</Picker.Clear>
<Picker.AcceptValue>Accept</Picker.AcceptValue>
<Picker.CancelValue>Cancel</Picker.CancelValue>
<Popover.Close>Close</Popover.Close>
</div>
</Popover.Popup>
With Material UI
TODO
Add a toolbar
Without Material UI
The user can use the <Picker.FormattedDate />
component to create a toolbar for its picker:
import { Popover } from '@base-ui-components/react/popover';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { usePickerContext } from '@base-ui-components/react-x-date-pickers/hooks';
function PickerToolbar() {
const { value } = usePickerContext();
return (
<Popover.Popup>
<div>{value.format('MMMM YYYY')}</div>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Popover.Popup>
);
}
The toolbar can also be used to switch between sections thanks to the <Picker.SetActiveSection />
component:
import { Popover } from '@base-ui-components/react/popover';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { usePickerContext } from '@base-ui-components/react-x-date-pickers/hooks';
function PickerToolbar() {
const { value } = usePickerContext();
return (
<Popover.Popup>
<div>
<Picker.SetActiveSection target="year">
{value.format('YYYY')}
</Picker.SetActiveSection>
<Picker.SetActiveSection target="day">
{value.format('DD MMMM')}
</Picker.SetActiveSection>
</div>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Popover.Popup>
);
}
With Material UI
TODO
Add tabs
Without Material UI
The user can use the <Picker.SetActiveSection />
component in combination with any Tabs / Tab components.
The example below uses the Tabs
component from Base UI as an example:
import { Tabs } from '@base-ui-components/react/tabs';
import { Popover } from '@base-ui-components/react/popover';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { isDateSection } from '@base-ui-components/react-x-date-pickers/utils';
<Popover.Popup>
<Picker.ContextValue>
{({ activeSection }) => (
<Tabs.Root value={isDateSection(activeSection) ? 'date' : 'time'}>
<Tabs.List>
<Tabs.Tab
value="date"
render={(props) => <Picker.SetActiveSection {...props} target="day" />}
>
Date
</Tabs.Tab>
<Tabs.Tab
value="time"
render={(props) => <Picker.SetActiveSection {...props} target="hours" />}
>
Time
</Tabs.Tab>
</Tabs.List>
</Tabs.Root>
)}
</Picker.ContextValue>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Popover.Popup>;
With Material UI
TODO
Add shortcuts
Without Material UI
The user can use the <Picker.SetValue />
component to create a shortcut UI:
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
import { Popover } from '@base-ui-components/react/popover';
<Popover.Popup>
<div>
<Picker.SetValue target={dayjs().month(0).date(1)}>
New Year's Day
</Picker.SetValue>
<Picker.SetValue target={dayjs().month(6).date(4)}>
Independence Day
</Picker.SetValue>
</div>
<Calendar.Root>{/** See calendar documentation */}</Calendar.Root>
</Popover.Popup>;
With Material UI
TODO
Anatomy of Picker.*
Picker.Root
Top level component that wraps the other components.
It expects a function as its children, which receives the context value as a parameter:
<Picker.Root manager={manager} {...props}>
{({ open, setOpen }) => <Popover.Root open={open} onOpenChange={setOpen} />}
</Picker.Root>
Props
manager
:PickerManager
- requiredchildren
:(contextValue: PickerContextValue) => React.ReactNode
Value props:
value
,defaultValue
,referenceDate
,onChange
,onError
andtimezone
.Same typing and behavior as today.
Validation props: list based on the
manager
propFor
useDateManager()
it would bemaxDate
,minDate
,disableFuture
,disablePast
,shouldDisableDate
,shouldDisableMonth
,shouldDisableYear
.Same typing and behavior as today.
Form props:
disabled
,readOnly
.Same typing and behavior as today.
Open props:
open
,onOpenChange
The
onOpenChange
replaces theonOpen
andonClose
props in the current implementation
Picker.StaticRoot
Props
Top level component that wraps the other components when there is not field UI but only views.
manager
:PickerManager
- requiredchildren
:(contextValue: PickerContextValue) => React.ReactNode
Value props:
value
,defaultValue
,referenceDate
,onChange
,onError
andtimezone
.Same typing and behavior as today.
Validation props: list based on the
manager
propFor
useDateManager()
it would bemaxDate
,minDate
,disableFuture
,disablePast
,shouldDisableDate
,shouldDisableMonth
,shouldDisableYear
.Same typing and behavior as today.
Form props:
disabled
,readOnly
.Same typing and behavior as today.
Picker.ContextValue
Utility component to access the picker public context.
Doesn't render a DOM node (it does not have a render
prop either).
Props
children
:(contextValue: PickerContextValue) => React.ReactNode
Picker.SetValue
Renders a button to set the current value.
Props
Extends
React.HTMLAttributes<HTMLButtonELement>
target
:PickerValidDate
- requiredskipValidation
:boolean
, default:false
(by default the button is disabled is the target value is not passing validation)changeImportance
:'set' | 'accept'
, default:'accept'
skipPublicationIfPristine
:boolean
, default:false
Usages in the styled version
The List Item of
<PickersShortcuts />
(people creating custom UIs can also use this component)The Button of
<PickersActionBar />
that sets the value to today or clear the value
Picker.AcceptValue
Renders a button to accept the current value.
Props
- Extends
React.HTMLAttributes<HTMLButtonELement>
Usages in the styled version
- The Button of
<PickersActionBar />
that accepts the value
Picker.CancelValue
Renders a button to cancel the current value.
Props
- Extends
React.HTMLAttributes<HTMLButtonELement>
Usages in the styled version
- The Button of
<PickersActionBar />
that cancels the value
Picker.SetActiveSection
Renders a button to set the active section.
Usages in the styled version
The Tab in
<DateTimePickerTabs />
The Tab in
<DateTimeRangePickerTabs />
(might require manually usingusePickerContext
to make the range position change work)
Props
Extends
React.HTMLAttributes<HTMLButtonELement>
target
:PickerSectionType
(currentFieldSectionType
that would be renamed) - required