Field
This page describes how people can use field with Material UI and how they can build custom fields while keeping the built-in editing behavior.
Basic standalone usage
Without Material UI
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { PickerField } from '@base-ui-components/react-x-date-pickers/picker-field';
function CustomDateField(props) {
const manager = useDateManager();
return (
<PickerField.Root manager={manager} {...props}>
<PickerField.Content>
{({ sections }) =>
sections.map((section) => (
<PickerField.Section section={section} key={section.key}>
<PickerField.SectionSeparator position="before" />
<PickerField.SectionContent />
<PickerField.SectionSeparator position="after" />
</PickerField.Section>
))
}
</PickerField.Content>
</PickerField.Root>
);
}
The field can then be rendered just like the Material UI fields:
<CustomDateField value={value} onChange={setValue} />
With Material UI
The @mui/x-date-pickers
package exposes one field per value type.
Those components are self-contained components (meaning they don't use composition).
Here is a basic example of a <DateField />
:
import { DateField } from '@mui/x-date-pickers/DateField';
<DateField value={value} onChange={setValue} />;
The behavior is the same for all the other fields:
<TimeField value={value} onChange={setValue} />;
<DateTimeField value={value} onChange={setValue} />;
<DateRangeField value={value} onChange={setValue} />;
<DateTimeRangeField value={value} onChange={setValue} />;
<TimeRangeField value={value} onChange={setValue} />;
Basic usage inside a picker
Without Material UI
Add a trigger to open the picker
To be able to open the picker using its field, the user has to add a trigger button for the Popover or the Modal that is used inside the picker. You can find more demos on the picker documentation on how to handle mobile and responsive pickers.
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { PickerField } from '@base-ui-components/react-x-date-pickers/picker-field';
function CustomDateField(props) {
const manager = useDateManager();
return (
<PickerField.Root manager={manager} {...props}>
<PickerField.Content>{/** See demo above */}</PickerField.Content>
<Popover.Trigger>📅</Popover.Trigger>
</PickerField.Root>
);
}
Inside a picker from @mui/x-date-pickers
Even if most applications with a custom field probably want to remove @mui/material
entirely, using these custom fields inside a self contained picker component from @mui/x-date-pickers/DatePicker
is totally doable.
This can be useful for application using Material UI but with some specific needs for the fields or to allow for a gradual migration away from Material UI.
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
<DatePicker slots={{ field: CustomDateField }} />;
Inside an unstyled picker
The custom field can also be used inside a picker built with the composable Picker.*
component from @base-ui-components/react-x-date-pickers/picker
:
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
function CustomDatePicker(props) {
const manager = useDateManager();
return (
<Popover.Root>
<Picker.Root manager={manager} {...props}>
<CustomField />
<Popover.Backdrop />
<Popover.Positioner>{/** See picker documentation */}</Popover.Positioner>
</Picker.Root>
</Popover.Root>
);
}
The user can also inline their field if they want:
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { Picker } from '@base-ui-components/react-x-date-pickers/picker';
function CustomDatePicker(props) {
const manager = useDateManager();
return (
<Popover.Root>
<Picker.Root manager={manager} {...props}>
<PickerField.Root manager={manager} {...props}>
<PickerField.Content>{/** See demo above */}</PickerField.Content>
<Popover.Trigger>📅</Popover.Trigger>
</PickerField.Root>
<Popover.Backdrop />
<Popover.Positioner>{/** See picker documentation */}</Popover.Positioner>
</Picker.Root>
</Popover.Root>
);
}
With Material UI
The field exposed by @mui/x-date-pickers
and @mui/x-date-pickers
automatically
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
<DatePicker slots={{ field: DateField }} />;
Basic usage (multi input picker)
Without Material UI
With Material UI
The @mui/x-date-pickers
package also exposes a component to create multi input range fields as follow:
import { useDateRangeManager } from '@mui/x-date-pickers/managers';
import { MultiInputRangeField } from '@mui/x-date-pickers/MultiInputRangeField';
function MultiInputDateTimeRangeField(props: MultiInputDateTimeRangeFieldProps) {
const manager = useDateTimeRangeManager(props);
return <MultiInputRangeField {...props} manager={manager} ref={ref} />;
}
When used inside a picker, <MultiInputRangeField />
can be passed directly and uses the manager
exposed by usePickerContext
:
<DatePicker slots={{ field: MultiInputRangeField }} />
Clearable field
Without Material UI
The user can use the <PickerField.Clear />
component to add a button to clear the value:
import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers';
import { PickerField } from '@base-ui-components/react-x-date-pickers/picker-field';
function CustomDateField(props) {
const manager = useDateManager();
return (
<PickerField.Root manager={manager} {...props}>
<PickerField.Content>{/** See demo above */}</PickerField.Content>
<PickerField.Clear>
<CustomIcon />
</PickerField.Clear>
</PickerField.Root>
);
}
With Material UI
<DateField clearable />
<DatePicker slotProps={{ field: { clearable: true } }}>
Anatomy of PickerField.*
PickerField.Root
Top level component that wraps the other components.
It would expend Field.Root
from @base-ui-components/react/Field
.
Props
Extends
Field.Root.Props
manager
:PickerManager
- required for standalone fieldsValue 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.
format
:string
(default value applied by themanager
).formatDensity
:'dense' | 'spacious'
, default:'dense'
.shouldRespectLeadingZeros
:boolean
, default:false
.selectedSections
:FieldSelectedSections
onSelectedSectionsChange
:(newValue: FieldSelectedSections) => void
unstableFieldRef
:React.Ref<FieldRef<TSection>>
This one may not be needed. If its only used for internal purpose, it can probably be made internal (the picker would pass a ref using a private context instead of a prop).
Keeping it unstable makes removing it easy.
autoFocus
:boolean
PickerField.Content
It would expend Field.Control
from @base-ui-components/react/Field
.
It expects a function as its children, which receives the list of sections to render as a parameter:
<PickerField.Content>
{({ sections }) =>
sections.map((section) => (
<PickerField.Section value={section} key={section.key} />
))
}
</PickerField.Content>
It also renders a hidden input which contains the stringified value and can be used for form submission and testing.
Props
Extends
Field.Control.Props
children
:(section: InferFieldSection<TValue>) => React.ReactNode
PickerField.Section
Renders a single section (for instance the year of the hour of the current value).
Props
- Extends
React.HTMLAttributes<HTMLSpanElement>
section
:InferFieldSection<TValue>
(can beFieldSection
orFieldRangeSection
) - required.
PickerField.SectionContent
Renders the content of a single section.
Props
- Extends
React.HTMLAttributes<HTMLSpanElement>
PickerField.SectionSeparator
Renders the separator to display before or after the current section.
<PickerField.SectionSeparator position="before" />
Props
- Extends
React.HTMLAttributes<HTMLSpanElement>
position
:'before' | 'after'
- required.
PickerField.Clear
Renders the button to clear the value of the field.
Props
Extends
React.HTMLAttributes<HTMLButtonElement>
children
:React.ReactNode
onClear
:React.MouseEventHandler