Unlike the native PropertyPaneTextField, this control returns a structured date value instead of a plain string. It can be configured to display only a date or both a date and a time.
In this example, we will create a Property Pane field that allows the web part author to select a date and time using a 12-hour clock.
The selected value will then be passed from the web part properties to a React component and displayed inside the web part.
Using PropertyFieldDateTimePicker in an SPFx Web Part
The PropertyFieldDateTimePicker control provides a date and time selector that can be added to the Property Pane of a SharePoint Framework web part.
Unlike the native PropertyPaneTextField, this control returns a structured date value instead of a plain string. It can be configured to display only a date or both a date and a time.
In this example, we will create a Property Pane field that allows the web part author to select a date and time using a 12-hour clock.
The selected value will then be passed from the web part properties to a React component and displayed inside the web part.
The control is part of the reusable PnP SPFx Property Controls library. (PNP)
Install the PnP SPFx Property Controls package
Run the following command from the root directory of your existing SPFx solution:
npm install @pnp/spfx-property-controls --save
After installing the package, restore the remaining project dependencies:
npm install
Import the PropertyFieldDateTimePicker control
The control, its conventions and its value interface can be imported from the same module:
import { PropertyFieldDateTimePicker, DateConvention, TimeConvention, IDateTimeFieldValue} from '@pnp/spfx-property-controls/lib/PropertyFieldDateTimePicker';
The following elements are used:
PropertyFieldDateTimePickercreates the Property Pane field.DateConventiondefines whether the control displays only a date or a date and time.TimeConventiondefines whether the control uses a 12-hour or 24-hour clock.IDateTimeFieldValuerepresents the selected value.
Define the web part properties
The web part needs a property to store the selected date and time.
export interface IPropertyFieldDateTimePickerWpWebPartProps { description: string; datetime: IDateTimeFieldValue;}
The datetime property must use IDateTimeFieldValue.
It should not be declared as a string or Date because the PnP control returns an object containing the selected date and its formatted display value.
Complete web part code
Open the main web part file:
src/webparts/propertyFieldDateTimePickerWp/PropertyFieldDateTimePickerWpWebPart.ts
Replace its contents with the following code:
import * as React from 'react';import * as ReactDom from 'react-dom';import { Version } from '@microsoft/sp-core-library';import { type IPropertyPaneConfiguration, PropertyPaneTextField} from '@microsoft/sp-property-pane';import { BaseClientSideWebPart} from '@microsoft/sp-webpart-base';import { IReadonlyTheme} from '@microsoft/sp-component-base';import * as strings from 'PropertyFieldDateTimePickerWpWebPartStrings';import PropertyFieldDateTimePickerWp from './components/PropertyFieldDateTimePickerWp';import { IPropertyFieldDateTimePickerWpProps} from './components/IPropertyFieldDateTimePickerWpProps';import { PropertyFieldDateTimePicker, DateConvention, TimeConvention, IDateTimeFieldValue} from '@pnp/spfx-property-controls/lib/PropertyFieldDateTimePicker';export interface IPropertyFieldDateTimePickerWpWebPartProps { description: string; datetime: IDateTimeFieldValue;}export default class PropertyFieldDateTimePickerWpWebPart extends BaseClientSideWebPart<IPropertyFieldDateTimePickerWpWebPartProps> { private _isDarkTheme: boolean = false; private _environmentMessage: string = ''; public render(): void { const element: React.ReactElement<IPropertyFieldDateTimePickerWpProps> = React.createElement( PropertyFieldDateTimePickerWp, { description: this.properties.description, isDarkTheme: this._isDarkTheme, environmentMessage: this._environmentMessage, userDisplayName: this.context.pageContext.user.displayName, datetime: this.properties.datetime } ); ReactDom.render( element, this.domElement ); } protected onInit(): Promise<void> { return this._getEnvironmentMessage() .then((message: string): void => { this._environmentMessage = message; }); } private _getEnvironmentMessage(): Promise<string> { if (this.context.sdks.microsoftTeams) { return this.context.sdks.microsoftTeams .teamsJs.app .getContext() .then((context): string => { let environmentMessage: string = ''; switch (context.app.host.name) { case 'Office': environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOffice : strings.AppOfficeEnvironment; break; case 'Outlook': environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOutlook : strings.AppOutlookEnvironment; break; case 'Teams': case 'TeamsModern': environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentTeams : strings.AppTeamsTabEnvironment; break; default: environmentMessage = strings.UnknownEnvironment; } return environmentMessage; }); } return Promise.resolve( this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentSharePoint : strings.AppSharePointEnvironment ); } protected onThemeChanged( currentTheme: IReadonlyTheme | undefined ): void { if (!currentTheme) { return; } this._isDarkTheme = !!currentTheme.isInverted; const { semanticColors } = currentTheme; if (semanticColors) { this.domElement.style.setProperty( '--bodyText', semanticColors.bodyText || null ); this.domElement.style.setProperty( '--link', semanticColors.link || null ); this.domElement.style.setProperty( '--linkHovered', semanticColors.linkHovered || null ); } } protected onDispose(): void { ReactDom.unmountComponentAtNode( this.domElement ); } protected get dataVersion(): Version { return Version.parse('1.0'); } protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ PropertyPaneTextField( 'description', { label: strings.DescriptionFieldLabel } ), PropertyFieldDateTimePicker( 'datetime', { label: 'Select the date and time', initialDate: this.properties.datetime, dateConvention: DateConvention.DateTime, timeConvention: TimeConvention.Hours12, onPropertyChange: this.onPropertyPaneFieldChanged, properties: this.properties, onGetErrorMessage: undefined, deferredValidationTime: 0, key: 'dateTimeFieldId', showLabels: false } ) ] } ] } ] }; }}
Understanding the Property Pane group
The control is added to the groupFields collection of a Property Pane group:
groups: [ { groupName: strings.BasicGroupName, groupFields: [ PropertyPaneTextField( 'description', { label: strings.DescriptionFieldLabel } ), PropertyFieldDateTimePicker( 'datetime', { // Control configuration } ) ] }]
The groupName property defines the group title displayed in the Property Pane.
The groupFields array contains the fields rendered inside that group.
In this example, the group contains:
- A native SPFx
PropertyPaneTextField. - A PnP
PropertyFieldDateTimePicker.
The PnP control documentation specifies that the custom field must be added to the groupFields collection of the web part Property Pane configuration. (PNP)
Configure the PropertyFieldDateTimePicker
The control configuration is:
PropertyFieldDateTimePicker( 'datetime', { label: 'Select the date and time', initialDate: this.properties.datetime, dateConvention: DateConvention.DateTime, timeConvention: TimeConvention.Hours12, onPropertyChange: this.onPropertyPaneFieldChanged, properties: this.properties, onGetErrorMessage: undefined, deferredValidationTime: 0, key: 'dateTimeFieldId', showLabels: false })
The first argument is the web part property name:
'datetime'
This connects the control to:
this.properties.datetime
When the user changes the selected date, the new value is stored in that web part property.
The label property
label: 'Select the date and time'
The label property defines the text displayed above the Property Pane control.
The initialDate property
initialDate: this.properties.datetime
The initialDate property provides the value that should initially be displayed by the control.
When the web part is edited again, the previously saved value is passed back to the control.
This value must use the IDateTimeFieldValue interface.
The dateConvention property
dateConvention: DateConvention.DateTime
The date convention controls whether the picker displays only a date or both date and time.
To display only the date, use:
dateConvention: DateConvention.Date
To display both date and time, use:
dateConvention: DateConvention.DateTime
The control officially supports date-only and date-and-time configurations. (PNP)
The timeConvention property
timeConvention: TimeConvention.Hours12
The time convention defines how the time is displayed.
For a 12-hour clock, use:
timeConvention: TimeConvention.Hours12
For a 24-hour clock, use:
timeConvention: TimeConvention.Hours24
The onPropertyChange property
onPropertyChange: this.onPropertyPaneFieldChanged
This callback informs the SPFx Property Pane that the property value has changed.
It allows SPFx to update:
this.properties.datetime
Without this connection, the control would not correctly participate in the standard SPFx property update process.
The properties property
properties: this.properties
This provides the complete web part property object to the PnP control.
The control uses this object together with onPropertyChange to update the selected property.
The validation properties
onGetErrorMessage: undefined,deferredValidationTime: 0
The onGetErrorMessage property can be used to implement custom validation.
In this example, no validation function is provided:
onGetErrorMessage: undefined
The deferredValidationTime property defines the delay before validation begins.
Because no validation is required, it is set to zero:
deferredValidationTime: 0
The key property
key: 'dateTimeFieldId'
The key uniquely identifies the Property Pane control.
Each custom Property Pane control should have a stable and unique key.
The showLabels property
showLabels: false
This property controls whether the internal date and time labels are displayed.
In this example, the additional labels are hidden.
Create the React props interface
Open:
src/webparts/propertyFieldDateTimePickerWp/components/IPropertyFieldDateTimePickerWpProps.ts
Add the following code:
import { IDateTimeFieldValue} from '@pnp/spfx-property-controls/lib/PropertyFieldDateTimePicker';export interface IPropertyFieldDateTimePickerWpProps { description: string; isDarkTheme: boolean; environmentMessage: string; userDisplayName: string; datetime?: IDateTimeFieldValue;}
The datetime property is optional because the web part may not have a selected date when it is added to the page for the first time.
datetime?: IDateTimeFieldValue;
Importing IDateTimeFieldValue from the specific control module also keeps the import consistent with the web part file.
Create the React component
Open:
src/webparts/propertyFieldDateTimePickerWp/components/PropertyFieldDateTimePickerWp.tsx
Use the following code:
import * as React from 'react';import { IPropertyFieldDateTimePickerWpProps} from './IPropertyFieldDateTimePickerWpProps';const PropertyFieldDateTimePickerWp:React.FunctionComponent<IPropertyFieldDateTimePickerWpProps> = ( props) => { return ( <div> <h1> Property Field Date Time Picker Web Part </h1> <p> This is a sample web part that demonstrates the use of the PropertyFieldDateTimePicker control. </p> <p> Description: {props.description} </p> <p> Is Dark Theme:{' '} {props.isDarkTheme ? 'Yes' : 'No'} </p> <p> Environment Message:{' '} {props.environmentMessage} </p> <p> User Display Name:{' '} {props.userDisplayName} </p> <p> Selected Date Time:{' '} { props.datetime ? props.datetime.displayValue : 'No date selected' } </p> </div> );};export default PropertyFieldDateTimePickerWp;
Display the selected date
The selected formatted value is available through:
props.datetime.displayValue
Because a date may not have been selected yet, the component checks whether the property contains a value:
{ props.datetime ? props.datetime.displayValue : 'No date selected'}
This prevents runtime errors when the web part is rendered before the user configures the control.
The explicit toString() call is unnecessary because displayValue can be rendered directly:
props.datetime.displayValue
Understanding IDateTimeFieldValue
The PropertyFieldDateTimePicker does not return only a formatted string.
It returns an IDateTimeFieldValue object.
The two most useful values are:
datetime.value
and:
datetime.displayValue
The value property represents the actual JavaScript date value.
The displayValue property represents the date and time formatted for display.
For example:
<p> Formatted value: {props.datetime?.displayValue}</p>
To work directly with the JavaScript Date object:
<p> Date object: {props.datetime?.value.toLocaleString()}</p>
How the data flows through the web part
The Property Pane control writes the selected value to:
this.properties.datetime
The web part passes that value to the React component:
datetime: this.properties.datetime
The React interface receives it:
datetime?: IDateTimeFieldValue;
The component displays the formatted value:
props.datetime.displayValue
The complete flow is:
PropertyFieldDateTimePicker ↓this.properties.datetime ↓React.createElement properties ↓IPropertyFieldDateTimePickerWpProps ↓React component ↓datetime.displayValue
Important correction: do not use an empty string
The following fallback should not be used:
datetime: this.properties.datetime || ''
The problem is that datetime expects:
IDateTimeFieldValue
but the fallback provides:
string
These types are incompatible.
Use:
datetime: this.properties.datetime
Then declare the React property as optional:
datetime?: IDateTimeFieldValue;
The React component can handle the undefined state safely.
Important correction: remove the duplicate interface
The following interface is not required:
export interface IPropertyControlsTestWebPartProps { datetime: IDateTimeFieldValue;}
The web part already uses:
export interface IPropertyFieldDateTimePickerWpWebPartProps { description: string; datetime: IDateTimeFieldValue;}
Keeping both interfaces creates unnecessary duplication and can make the code more confusing.
Optional default date
A default value can be initialized inside onInit.
protected onInit(): Promise<void> { if (!this.properties.datetime) { const currentDate: Date = new Date(); this.properties.datetime = { value: currentDate, displayValue: currentDate.toLocaleString() }; } return this._getEnvironmentMessage() .then((message: string): void => { this._environmentMessage = message; });}
This is optional.
Without a default value, the control simply starts without a selected date.
Use a 24-hour clock
To change the control to a 24-hour format, replace:
timeConvention: TimeConvention.Hours12
with:
timeConvention: TimeConvention.Hours24
Use date only
To remove the time selection, replace:
dateConvention: DateConvention.DateTime
with:
dateConvention: DateConvention.Date
The configuration would become:
PropertyFieldDateTimePicker( 'datetime', { label: 'Select a date', initialDate: this.properties.datetime, dateConvention: DateConvention.Date, timeConvention: TimeConvention.Hours24, onPropertyChange: this.onPropertyPaneFieldChanged, properties: this.properties, onGetErrorMessage: undefined, deferredValidationTime: 0, key: 'dateFieldId', showLabels: false })
Run the web part
Start the SPFx development server using Heft:
heft start
Open the SharePoint hosted workbench, add the web part and edit its properties.
The Property Pane will display:
Select the date and time
After selecting a value, the control stores it in:
this.properties.datetime
The React component then displays:
Selected Date Time: [formatted date and time]
Common TypeScript problem
A common error occurs when a string is assigned to IDateTimeFieldValue.
Example of incorrect code:
datetime: this.properties.datetime || ''
Possible TypeScript result:
Type 'string | IDateTimeFieldValue'is not assignable to type'IDateTimeFieldValue'
Correct code:
datetime: this.properties.datetime
And in the React props interface:
datetime?: IDateTimeFieldValue;
Final result
The web part now contains:
- A native description text field.
- A PnP date and time selector.
- A value stored in the web part properties.
- A strongly typed
IDateTimeFieldValue. - A React component that displays the selected date.
- Support for date-only or date-and-time configurations.
- Support for 12-hour or 24-hour time formats.
The most important part of this implementation is preserving the correct type throughout the complete data flow:
IDateTimeFieldValue
The value should remain strongly typed from the Property Pane configuration through the web part properties and into the React component.
Official documentation
PropertyFieldDateTimePicker:
PnP SPFx Property Controls:
The official documentation describes the control as a date and time picker for SPFx Property Panes and provides configurations for date-only and date-and-time selection. (PNP)
This article keeps your original demonstration structure while correcting the IDateTimeFieldValue typing and the unsafe empty-string fallback.
