Date time component

The date picker provides access to calendar component but is there any built in component to allow users to select datetime ?

No, there isn’t. You need to use an external component for that.

Well thats bad. Its a common usecase.

But looks like some thing is in works, not sure if it is yet ready for use.

https://github.com/vaadin/vaadin-time-picker

kiran surapaneni:
But looks like some thing is in works, not sure if it is yet ready for use.

https://github.com/vaadin/vaadin-time-picker

Great! But looks that is client-side only.

Every Vaadin Flow component is a wrapper around a corresponding client-side one. So, the first step of developing a totally new component from scratch is to develop its client-side part. There are other ways of creating a component by assembling single or multiple elements/components as well as from templates. These are described in the Vaadin Flow documentation.

This should be a standard feature of the vaadin component.
I hope it will be done in the future.

But if you want a quickly solution, i was working on this to train me on vaadin 10 and polymer.

i made a subclass to add the time feature to the vaadin date picker.

here is my code.
should work. But you will need to adapt for your use.
I used in french format (dd/mm/yyyy HH:mm)

client side :

<dom-module id="custom-date-picker"> 
	<template>
	</template> 
	<script>
      	class CustomDatePicker extends Vaadin.DatePickerElement  {
	        static get is() { return 'custom-date-picker'}
			
			static get template() {
				return Vaadin.DatePickerElement.template;
			}
			
	        static get observers() {
	        	return [
	              'textUpdateEvent(_userInputValue)'
	            ];
	     	}
	        	        
	        static get properties() {
	            return {
	              /**
	               * Set to false to disable this element.
	               */
	               showTime: {
	                type: Boolean,
	                value: true,
	                reflectToAttribute: true
	              },
	              hour: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
	              minute: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
		          _saveSelectedDate: {
		                type: Date
		              },
		          _selectHour: {
		                type: Object
		              },
		          _selectMinute: {
		                type: Object
		              },
	              _lastTime: {
		                type: String
		              }	,
	              _oldValue: {
		                type: String
		              },
	              _changeTxtManual: {
	                type: Boolean,
	                value: false
	              }
	            }
	        }
	        
	        _clear() {
	        	this._saveSelectedDate = null;
	        	super._clear();
	        }
	        
	        ready(){
	        	super.ready();
	        	
	        	//French
	        	super.set('i18n.firstDayOfWeek', 1);
	        	super.set('i18n.monthNames', ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
);
	        	super.set('i18n.week', 'semaine');
	        	super.set('i18n.weekdays', ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi']
);
	        	super.set('i18n.weekdaysShort', ['di','lu','ma','me','je','ve','sa']
);
	        	super.set('i18n.calendar', 'calendrier');
	        	super.set('i18n.clear', 'Effacer');
	        	super.set('i18n.today', 'Aujourd\'hui');
	        	super.set('i18n.cancel', 'Annuler');
	        }
	        
	        
	        _setTimeFeature(){
	        	//Add time feature
	        	var tmp = document.createElement('div');	
	        	//TODO Put style in template
	            tmp.innerHTML = '<div style="width: 120px;margin: auto;" class="cdp_TimeChooser"><select id="cdp_hour"></select>:<select id="cdp_minute"></select></div>';
	            Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.appendChild(tmp);
	            
	            this._selectHour = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_hour');
	            this._selectMinute = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_minute');
	            

	            for(let i = 0; i < 24; i++){
	            	var tmp_option = document.createElement('option');
	            	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
	            	this._selectHour.append(tmp_option);
	            }
	            
	            for(let i = 0; i < 60; i++){
	            	var tmp_option = document.createElement('option');
	            	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
	            	this._selectMinute.append(tmp_option);
	            }
	            
	            
	            //Events change
	            this._selectHour.addEventListener('change', this._onHourChange.bind(this));
	            this._selectMinute.addEventListener('change', this._onMinuteChange.bind(this));
	        }
	        	        
	        _onHourChange(event){	
	        	if(! this._changeTxtManual){
		        	this.hour = event.target.value;	        	
	
		        	if(this.showTime && super._userInputValue.length == 16){
		        		super._userInputValue = super._userInputValue.substr(0, 11) + this.hour + ':' + super._userInputValue.substr(14,2);
		        	}	     
	        	}
	        }
	        
	        _onMinuteChange(event){
	        	if(! this._changeTxtManual){
		        	this.minute = event.target.value;
		        	
		        	if(this.showTime && super._userInputValue.length == 16){
		        		super._userInputValue = super._userInputValue.substr(0, 14) + this.minute;
		        	}	
	        	}
	        }
	        
	        validate(value) {
	        	value = value !== undefined ? value : this._inputValue;
	        	
        	 	if(value.length > 10){
	            	value = value.substr(0, 10);
	            }
	        	
	        	if(this._saveSelectedDate){
	        		super._selectedDate = this._saveSelectedDate;
	        	}
	        	else{
	        		//Need to parse date here.
	        		
	        	}

	            return super.validate(value);
	        }
	        
	       textUpdateEvent(_userInputValue){		        	       		        	
	        	//Time
	        	if(this.showTime && _userInputValue.length == 10){
	        		this._saveSelectedDate = super._selectedDate;
	        		super._userInputValue = _userInputValue + ' ' + this.hour + ':' + this.minute;		
	        	}
	        	
	        	if(this.showTime && super._userInputValue.length == 16 && (! this._lastTime  || this._lastTime !== super._userInputValue)){
	        		this._lastTime = super._userInputValue;
	        		this.$server.clientSetDateTime(super._userInputValue);
	        		this.updateSelectTime();	        		
	        	}		        	
	        }
	        
	        setDateTime(dateTime){	        
	        	super._userInputValue = dateTime;
	        	this.updateSelectTime();
	        }
	        
	        
	        updateSelectTime(){
	        	this.hour = super._userInputValue.substr(11, 2);
	        	this.minute = super._userInputValue.substr(14, 2);
	        	
	        	var h = parseInt(this.hour);
	        	var m = parseInt(this.minute);
	        	
	        	this._changeTxtManual = true;
	        	this._selectHour.options[h]
.selected = true;
	        	this._selectMinute.options[m]
.selected = true;
	        	this._changeTxtManual = false;
	        }
		}
      	customElements.define(CustomDatePicker.is, CustomDatePicker);
	</script>
</dom-module>

server side :

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.vaadin.flow.component.ClientDelegate;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.HtmlImport;


@Tag("custom-date-picker")
@HtmlImport("frontend://src/composants/CustomDatePicker.html")
public class CustomDatePicker extends DatePicker{
	private static final long serialVersionUID = 1L;

	public static String formatDay = "dd/MM/yyyy";
	public static String formatDayHour = "dd/MM/yyyy HH:mm";
	
	public static DateTimeFormatter patternDay = DateTimeFormatter.ofPattern(formatDay);
	public static DateTimeFormatter patterDayHour = DateTimeFormatter.ofPattern(formatDayHour);
	

	String dateTime = null;
	boolean time;
	
	
	public CustomDatePicker() {
		this(false);
	}
	
	public CustomDatePicker(boolean time) {
		setWidth("210px");
		
		if(time){			
			this.getElement().callFunction("_setTimeFeature");		
		}
	}
	
	public void setDateTime(String dateTime){	
		setValue(LocalDate.parse(dateTime.substring(0, 10), patternDay));
		
		if(dateTime.length() == formatDayHour.length()){
			this.getElement().callFunction("setDateTime", dateTime);
		}
		
		this.dateTime = dateTime;
	}
	
	public void setDateTime(LocalDateTime dateTime){
		setDateTime(dateTime.format(patterDayHour));
	}
	
	public String getDateTimeString(){
		return dateTime;
	}
	
	public LocalDateTime getDateTime(){
		return LocalDateTime.parse(dateTime, patterDayHour);
	}

	@ClientDelegate
	private void clientSetDateTime(String time){
		this.dateTime = time;				
	}
}

you can see the result in the attached image below

17109678.png

Just to confirm – there will be a Flow component on top of <vaadin-time-picker>.

We assume this would be good enough for a while, so you can combine the date and time pickers to have a custom datetime picker when needed. We are probably going to postpone implementing a built-in datetime picker component.

its bad, This should be a standard feature of the vaadin 10. :frowning: atleast should have been used DateTimeField of vaadin 8.

I am using vaadin Java components, please give me example how to use vaadin-time-picker ?

The time picker component is not yet ready. The first alpha version was released this week, and the Flow integration has not been started yet. If you want, you can create a webjar for https://github.com/vaadin/vaadin-time-picker/releases/tag/v1.0.0-alpha1 yourself and then use the low-level element API in Flow to use it.

Thank you for reply, i am using fooloomanzoodatetime-picker for now. https://vaadin.com/directory/component/fooloomanzoodatetime-picker

if anyone interested,here is my working code.

example-template.html

<!-- Dependency resources -->
<base href="https://raw-dot-custom-elements.appspot.com/fooloomanzoo/datetime-picker/2.9.1/datetime-picker/">

<link rel="import" href="datetime-picker.html">
<link rel="import" href="overlay-date-picker.html">
<link rel="import" href="overlay-datetime-picker.html">
<link rel="import" href="overlay-time-picker.html">
<link rel="import" href="../bower_components/polymer/polymer-element.html">

<!-- Defines the example-template element -->
<dom-module id="example-template">
    <template>
        <style >

    datetime-picker,
    overlay-time-picker,
    overlay-datetime-picker,
    overlay-date-picker {
      vertical-align: middle;
      font-size: 14px;
      --input-background: #d5d5d5;
      --input-color: #222;
      --input-picker-background: #d5d5d5;
      --input-picker-color: #222;
      --input-focus-background: white;
      --input-focus-color: #222;
      --inner-input-focus-background: white;
      --inner-input-focus-border-color: transparent;
      --inner-input-focus-color: #222;
    }

    .last-listen overlay-datetime-picker {
      --input-background: #82d5f4;
      --input-color: #222;
      --input-picker-background: #82d5f4;
      --input-picker-color: #222;
      --input-focus-background: #4285f4;
      --input-focus-color: #f1f1f1;
    }

        </style>
        <overlay-datetime-picker value="{{value}}"></overlay-datetime-picker>
        <p>value: [[value]
]</p>
    </template>

    <!-- Polymer boilerplate to register the example-template element -->
    <script>
        class ExampleTemplate extends Polymer.Element {
            static get is() {
                return 'example-template'
            }
        }
        customElements.define(ExampleTemplate.is, ExampleTemplate);

    </script>
</dom-module>

ExampleTemplate.java

/**
 * Simple template example.
 */
@Tag("example-template")
@HtmlImport("src/example-template.html")
@SpringComponent
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ExampleTemplate extends PolymerTemplate<ExampleTemplate.ExampleModel> {


    /**
     * Template model which defines the single "value" property.
     */
    public interface ExampleModel extends TemplateModel {

        void setValue(Double value);
        Double getValue();
    }

    public ExampleTemplate() {
        // Set the initial value to the "value" property.
        getModel().setValue(Double.valueOf(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
        getElement().addPropertyChangeListener("value", event -> {
            System.out
                    .println("DateTime is set to: " +
                            LocalDateTime.ofInstant(Instant.ofEpochMilli(getModel().getValue().longValue()),
                                    TimeZone.getDefault().toZoneId()));

        });
    }

    public void setValue(String value) {
        getModel().setValue(Double.valueOf(value));
    }

    public Double getValue() {
        return  getModel().getValue();
    }
   
}

Any progress with this? Something like this from Alain HIRSCH: https://vaadin.com/attachment/cbeb9f91-5cab-43fc-bcd0-f9ba14a6657f/datetimeVaadin.png

Alain HIRSCH:
This should be a standard feature of the vaadin component.
I hope it will be done in the future.

But if you want a quickly solution, i was working on this to train me on vaadin 10 and polymer.

i made a subclass to add the time feature to the vaadin date picker.

here is my code.
should work. But you will need to adapt for your use.
I used in french format (dd/mm/yyyy HH:mm)

client side :

<dom-module id="custom-date-picker"> 
	<template>
	</template> 
	<script>
      	class CustomDatePicker extends Vaadin.DatePickerElement  {
	        static get is() { return 'custom-date-picker'}
			
			static get template() {
				return Vaadin.DatePickerElement.template;
			}
			
	        static get observers() {
	        	return [
	              'textUpdateEvent(_userInputValue)'
	            ];
	     	}
	        	        
	        static get properties() {
	            return {
	              /**
	               * Set to false to disable this element.
	               */
	               showTime: {
	                type: Boolean,
	                value: true,
	                reflectToAttribute: true
	              },
	              hour: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
	              minute: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
		          _saveSelectedDate: {
		                type: Date
		              },
		          _selectHour: {
		                type: Object
		              },
		          _selectMinute: {
		                type: Object
		              },
	              _lastTime: {
		                type: String
		              }	,
	              _oldValue: {
		                type: String
		              },
	              _changeTxtManual: {
	                type: Boolean,
	                value: false
	              }
	            }
	        }
	        
	        _clear() {
	        	this._saveSelectedDate = null;
	        	super._clear();
	        }
	        
	        ready(){
	        	super.ready();
	        	
	        	//French
	        	super.set('i18n.firstDayOfWeek', 1);
	        	super.set('i18n.monthNames', ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre']

);

      	super.set('i18n.week', 'semaine');
      	super.set('i18n.weekdays', ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi']

);

      	super.set('i18n.weekdaysShort', ['di','lu','ma','me','je','ve','sa']

);

      	super.set('i18n.calendar', 'calendrier');
      	super.set('i18n.clear', 'Effacer');
      	super.set('i18n.today', 'Aujourd\'hui');
      	super.set('i18n.cancel', 'Annuler');
      }
      
      
      _setTimeFeature(){
      	//Add time feature
      	var tmp = document.createElement('div');	
      	//TODO Put style in template
          tmp.innerHTML = '<div style="width: 120px;margin: auto;" class="cdp_TimeChooser"><select id="cdp_hour"></select>:<select id="cdp_minute"></select></div>';
          Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.appendChild(tmp);
          
          this._selectHour = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_hour');
          this._selectMinute = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_minute');
          

          for(let i = 0; i < 24; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectHour.append(tmp_option);
          }
          
          for(let i = 0; i < 60; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectMinute.append(tmp_option);
          }
          
          
          //Events change
          this._selectHour.addEventListener('change', this._onHourChange.bind(this));
          this._selectMinute.addEventListener('change', this._onMinuteChange.bind(this));
      }
      	        
      _onHourChange(event){	
      	if(! this._changeTxtManual){
          	this.hour = event.target.value;	        	

          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 11) + this.hour + ':' + super._userInputValue.substr(14,2);
          	}	     
      	}
      }
      
      _onMinuteChange(event){
      	if(! this._changeTxtManual){
          	this.minute = event.target.value;
          	
          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 14) + this.minute;
          	}	
      	}
      }
      
      validate(value) {
      	value = value !== undefined ? value : this._inputValue;
      	
    	 	if(value.length > 10){
          	value = value.substr(0, 10);
          }
      	
      	if(this._saveSelectedDate){
      		super._selectedDate = this._saveSelectedDate;
      	}
      	else{
      		//Need to parse date here.
      		
      	}

          return super.validate(value);
      }
      
     textUpdateEvent(_userInputValue){		        	       		        	
      	//Time
      	if(this.showTime && _userInputValue.length == 10){
      		this._saveSelectedDate = super._selectedDate;
      		super._userInputValue = _userInputValue + ' ' + this.hour + ':' + this.minute;		
      	}
      	
      	if(this.showTime && super._userInputValue.length == 16 && (! this._lastTime  || this._lastTime !== super._userInputValue)){
      		this._lastTime = super._userInputValue;
      		this.$server.clientSetDateTime(super._userInputValue);
      		this.updateSelectTime();	        		
      	}		        	
      }
      
      setDateTime(dateTime){	        
      	super._userInputValue = dateTime;
      	this.updateSelectTime();
      }
      
      
      updateSelectTime(){
      	this.hour = super._userInputValue.substr(11, 2);
      	this.minute = super._userInputValue.substr(14, 2);
      	
      	var h = parseInt(this.hour);
      	var m = parseInt(this.minute);
      	
      	this._changeTxtManual = true;
      	this._selectHour.options[h]

.selected = true;

      	this._selectMinute.options[m]

.selected = true;

      	this._changeTxtManual = false;
      }
  }
  	customElements.define(CustomDatePicker.is, CustomDatePicker);
```

server side :

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.vaadin.flow.component.ClientDelegate;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.HtmlImport;


@Tag("custom-date-picker")
@HtmlImport("frontend://src/composants/CustomDatePicker.html")
public class CustomDatePicker extends DatePicker{
	private static final long serialVersionUID = 1L;

	public static String formatDay = "dd/MM/yyyy";
	public static String formatDayHour = "dd/MM/yyyy HH:mm";
	
	public static DateTimeFormatter patternDay = DateTimeFormatter.ofPattern(formatDay);
	public static DateTimeFormatter patterDayHour = DateTimeFormatter.ofPattern(formatDayHour);
	

	String dateTime = null;
	boolean time;
	
	
	public CustomDatePicker() {
		this(false);
	}
	
	public CustomDatePicker(boolean time) {
		setWidth("210px");
		
		if(time){			
			this.getElement().callFunction("_setTimeFeature");		
		}
	}
	
	public void setDateTime(String dateTime){	
		setValue(LocalDate.parse(dateTime.substring(0, 10), patternDay));
		
		if(dateTime.length() == formatDayHour.length()){
			this.getElement().callFunction("setDateTime", dateTime);
		}
		
		this.dateTime = dateTime;
	}
	
	public void setDateTime(LocalDateTime dateTime){
		setDateTime(dateTime.format(patterDayHour));
	}
	
	public String getDateTimeString(){
		return dateTime;
	}
	
	public LocalDateTime getDateTime(){
		return LocalDateTime.parse(dateTime, patterDayHour);
	}

	@ClientDelegate
	private void clientSetDateTime(String time){
		this.dateTime = time;				
	}
}

you can see the result in the attached image below

Time field not shown at all and I get this error in console:

Uncaught TypeError: Cannot read property ‘options’ of undefined
at HTMLElement.updateSelectTime (date-time-picker.html:188)

> this line: this._selectHour.options[h]

.selected = true;

Nemanja Kostic:

Alain HIRSCH:
This should be a standard feature of the vaadin component.
I hope it will be done in the future.

But if you want a quickly solution, i was working on this to train me on vaadin 10 and polymer.

i made a subclass to add the time feature to the vaadin date picker.

here is my code.
should work. But you will need to adapt for your use.
I used in french format (dd/mm/yyyy HH:mm)

client side :

<dom-module id="custom-date-picker"> 
	<template>
	</template> 
	<script>
      	class CustomDatePicker extends Vaadin.DatePickerElement  {
	        static get is() { return 'custom-date-picker'}
			
			static get template() {
				return Vaadin.DatePickerElement.template;
			}
			
	        static get observers() {
	        	return [
	              'textUpdateEvent(_userInputValue)'
	            ];
	     	}
	        	        
	        static get properties() {
	            return {
	              /**
	               * Set to false to disable this element.
	               */
	               showTime: {
	                type: Boolean,
	                value: true,
	                reflectToAttribute: true
	              },
	              hour: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
	              minute: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
		          _saveSelectedDate: {
		                type: Date
		              },
		          _selectHour: {
		                type: Object
		              },
		          _selectMinute: {
		                type: Object
		              },
	              _lastTime: {
		                type: String
		              }	,
	              _oldValue: {
		                type: String
		              },
	              _changeTxtManual: {
	                type: Boolean,
	                value: false
	              }
	            }
	        }
	        
	        _clear() {
	        	this._saveSelectedDate = null;
	        	super._clear();
	        }
	        
	        ready(){
	        	super.ready();
	        	
	        	//French
	        	super.set('i18n.firstDayOfWeek', 1);
	        	super.set('i18n.monthNames', ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre']

);

      	super.set('i18n.week', 'semaine');
      	super.set('i18n.weekdays', ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi']

);

      	super.set('i18n.weekdaysShort', ['di','lu','ma','me','je','ve','sa']

);

      	super.set('i18n.calendar', 'calendrier');
      	super.set('i18n.clear', 'Effacer');
      	super.set('i18n.today', 'Aujourd\'hui');
      	super.set('i18n.cancel', 'Annuler');
      }
      
      
      _setTimeFeature(){
      	//Add time feature
      	var tmp = document.createElement('div');	
      	//TODO Put style in template
          tmp.innerHTML = '<div style="width: 120px;margin: auto;" class="cdp_TimeChooser"><select id="cdp_hour"></select>:<select id="cdp_minute"></select></div>';
          Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.appendChild(tmp);
          
          this._selectHour = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_hour');
          this._selectMinute = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_minute');
          

          for(let i = 0; i < 24; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectHour.append(tmp_option);
          }
          
          for(let i = 0; i < 60; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectMinute.append(tmp_option);
          }
          
          
          //Events change
          this._selectHour.addEventListener('change', this._onHourChange.bind(this));
          this._selectMinute.addEventListener('change', this._onMinuteChange.bind(this));
      }
      	        
      _onHourChange(event){	
      	if(! this._changeTxtManual){
          	this.hour = event.target.value;	        	

          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 11) + this.hour + ':' + super._userInputValue.substr(14,2);
          	}	     
      	}
      }
      
      _onMinuteChange(event){
      	if(! this._changeTxtManual){
          	this.minute = event.target.value;
          	
          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 14) + this.minute;
          	}	
      	}
      }
      
      validate(value) {
      	value = value !== undefined ? value : this._inputValue;
      	
    	 	if(value.length > 10){
          	value = value.substr(0, 10);
          }
      	
      	if(this._saveSelectedDate){
      		super._selectedDate = this._saveSelectedDate;
      	}
      	else{
      		//Need to parse date here.
      		
      	}

          return super.validate(value);
      }
      
     textUpdateEvent(_userInputValue){		        	       		        	
      	//Time
      	if(this.showTime && _userInputValue.length == 10){
      		this._saveSelectedDate = super._selectedDate;
      		super._userInputValue = _userInputValue + ' ' + this.hour + ':' + this.minute;		
      	}
      	
      	if(this.showTime && super._userInputValue.length == 16 && (! this._lastTime  || this._lastTime !== super._userInputValue)){
      		this._lastTime = super._userInputValue;
      		this.$server.clientSetDateTime(super._userInputValue);
      		this.updateSelectTime();	        		
      	}		        	
      }
      
      setDateTime(dateTime){	        
      	super._userInputValue = dateTime;
      	this.updateSelectTime();
      }
      
      
      updateSelectTime(){
      	this.hour = super._userInputValue.substr(11, 2);
      	this.minute = super._userInputValue.substr(14, 2);
      	
      	var h = parseInt(this.hour);
      	var m = parseInt(this.minute);
      	
      	this._changeTxtManual = true;
      	this._selectHour.options[h]

.selected = true;

      	this._selectMinute.options[m]

.selected = true;

      	this._changeTxtManual = false;
      }
  }
  	customElements.define(CustomDatePicker.is, CustomDatePicker);
</script>
```

server side :

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.vaadin.flow.component.ClientDelegate;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.HtmlImport;


@Tag("custom-date-picker")
@HtmlImport("frontend://src/composants/CustomDatePicker.html")
public class CustomDatePicker extends DatePicker{
	private static final long serialVersionUID = 1L;

	public static String formatDay = "dd/MM/yyyy";
	public static String formatDayHour = "dd/MM/yyyy HH:mm";
	
	public static DateTimeFormatter patternDay = DateTimeFormatter.ofPattern(formatDay);
	public static DateTimeFormatter patterDayHour = DateTimeFormatter.ofPattern(formatDayHour);
	

	String dateTime = null;
	boolean time;
	
	
	public CustomDatePicker() {
		this(false);
	}
	
	public CustomDatePicker(boolean time) {
		setWidth("210px");
		
		if(time){			
			this.getElement().callFunction("_setTimeFeature");		
		}
	}
	
	public void setDateTime(String dateTime){	
		setValue(LocalDate.parse(dateTime.substring(0, 10), patternDay));
		
		if(dateTime.length() == formatDayHour.length()){
			this.getElement().callFunction("setDateTime", dateTime);
		}
		
		this.dateTime = dateTime;
	}
	
	public void setDateTime(LocalDateTime dateTime){
		setDateTime(dateTime.format(patterDayHour));
	}
	
	public String getDateTimeString(){
		return dateTime;
	}
	
	public LocalDateTime getDateTime(){
		return LocalDateTime.parse(dateTime, patterDayHour);
	}

	@ClientDelegate
	private void clientSetDateTime(String time){
		this.dateTime = time;				
	}
}

you can see the result in the attached image below

Time field not shown at all and I get this error in console:

Uncaught TypeError: Cannot read property ‘options’ of undefined
at HTMLElement.updateSelectTime (date-time-picker.html:188)

this line: this._selectHour.options[h]
.selected = true;

Is it working code?

Unfortunately no.

What I was suggesting was something like this: https://vaadin-datetime-picker.glitch.me

![datetime-picker]
(https://www.dropbox.com/s/qc20kfs03oxpdug/datetime-picker.png?raw=1)

Source: https://glitch.com/edit/#!/vaadin-datetime-picker

Would that be good enough? Of course there should be an API to get/set a datetime value which proxies the internal field values (and all other field properties like required, invalid, error-message, etc.). I was lazy and didn’t implement that. I assume it would be straightforward.

(It’s Polymer 3 based, but easy to adapt to Polymer 2 if needed).

Thanks, this is good enough and styled nicely. Is source available somewhere, since you already did almost everything? Now I’m lazy :slight_smile:

It’s very strange dough that there is not yet official component. It’s usage is very common, used it many times in Vaadin 8 and previous versions. For example, when selecting date time range you expect to open one popup for ‘from’ and second one for ‘to’ not 4 selections (2 x date 2 x time)…

Added a link to the source in the previous message.

We wanted to do this, but we haven’t found the time yet. A lot of other priorities are getting in the way of many of these common UI components.

Thank you, this do well for now!