I am doing a phonegap app. When I am trying type="date"
input field as shown below, it shows date picker in iPhone as I expected but it doesn't show the placeholder I have given. I found the same issue here in SO, but no solution anywhere.
<input placeholder="Date" class="textbox-n" type="date" id="date">
This question is related to
html
cordova
datepicker
placeholder
I took jbarlow idea, but I added an if in the onblur function so the fields only change its type if the value is empty
<input placeholder="Date" class="textbox-n" type="text" onfocus="(this.type='date')" onblur="(this.value == '' ? this.type='text' : this.type='date')" id="date">
I'm surprised there's only one answer with an approach similar to the one I used.
I got the inspiration from @Dtipson's comment on @Mumthezir VP's answer.
I use two inputs for this, one is a fake input with type="text"
on which I set the placeholder, the other one is the real field with type="date"
.
On the mouseenter
event on their container, I hide the fake input and show the real one, and I do the opposite on the mouseleave
event. Obviously, I leave the real input visibile if it has a value set on it.
I wrote the code to use pure Javascript but if you use jQuery (I do) it's very easy to "convert" it.
// "isMobile" function taken from this reply:_x000D_
// https://stackoverflow.com/a/20293441/3514976_x000D_
function isMobile() {_x000D_
try { document.createEvent("TouchEvent"); return true; }_x000D_
catch(e) { return false; }_x000D_
}_x000D_
_x000D_
var deviceIsMobile = isMobile();_x000D_
_x000D_
function mouseEnterListener(event) {_x000D_
var realDate = this.querySelector('.real-date');_x000D_
// if it has a value it's already visible._x000D_
if(!realDate.value) {_x000D_
this.querySelector('.fake-date').style.display = 'none';_x000D_
realDate.style.display = 'block';_x000D_
}_x000D_
}_x000D_
_x000D_
function mouseLeaveListener(event) {_x000D_
var realDate = this.querySelector('.real-date');_x000D_
// hide it if it doesn't have focus (except_x000D_
// on mobile devices) and has no value._x000D_
if((deviceIsMobile || document.activeElement !== realDate) && !realDate.value) {_x000D_
realDate.style.display = 'none';_x000D_
this.querySelector('.fake-date').style.display = 'block';_x000D_
}_x000D_
}_x000D_
_x000D_
function fakeFieldActionListener(event) {_x000D_
event.preventDefault();_x000D_
this.parentElement.dispatchEvent(new Event('mouseenter'));_x000D_
var realDate = this.parentElement.querySelector('.real-date');_x000D_
// to open the datepicker on mobile devices_x000D_
// I need to focus and then click on the field._x000D_
realDate.focus();_x000D_
realDate.click();_x000D_
}_x000D_
_x000D_
var containers = document.getElementsByClassName('date-container');_x000D_
for(var i = 0; i < containers.length; ++i) {_x000D_
var container = containers[i];_x000D_
_x000D_
container.addEventListener('mouseenter', mouseEnterListener);_x000D_
container.addEventListener('mouseleave', mouseLeaveListener);_x000D_
_x000D_
var fakeDate = container.querySelector('.fake-date');_x000D_
// for mobile devices, clicking (tapping)_x000D_
// on the fake input must show the real one._x000D_
fakeDate.addEventListener('click', fakeFieldActionListener);_x000D_
// let's also listen to the "focus" event_x000D_
// in case it's selected using a keyboard._x000D_
fakeDate.addEventListener('focus', fakeFieldActionListener);_x000D_
_x000D_
var realDate = container.querySelector('.real-date');_x000D_
// trigger the "mouseleave" event on the_x000D_
// container when the value changes._x000D_
realDate.addEventListener('change', function() {_x000D_
container.dispatchEvent(new Event('mouseleave'));_x000D_
});_x000D_
// also trigger the "mouseleave" event on_x000D_
// the container when the input loses focus._x000D_
realDate.addEventListener('blur', function() {_x000D_
container.dispatchEvent(new Event('mouseleave'));_x000D_
});_x000D_
}
_x000D_
.real-date {_x000D_
display: none;_x000D_
}_x000D_
_x000D_
/* a simple example of css to make _x000D_
them look like it's the same element */_x000D_
.real-date, _x000D_
.fake-date {_x000D_
width: 200px;_x000D_
height: 20px;_x000D_
padding: 0px;_x000D_
}
_x000D_
<div class="date-container">_x000D_
<input type="text" class="fake-date" placeholder="Insert date">_x000D_
<input type="date" class="real-date">_x000D_
</div>
_x000D_
I tested this also on an Android phone and it works, when the user taps on the field the datepicker is shown. The only thing is, if the real input had no value and the user closes the datepicker without choosing a date, the input will remain visible until they tap outside of it. There's no event to listen to to know when the datepicker closes so I don't know how to solve that.
I don't have an iOS device to test it on.
Im working with ionicframework and solution provided by @Mumthezir is almost perfect. In case if somebody would have same problem as me(after change, input is still focused and when scrolling, value simply dissapears) So I added onchange to make input.blur()
<input placeholder="Date" class="textbox-n" type="text" onfocus=" (this.type='date')" onchange="this.blur();" id="date">
From Angular point of view I managed to put a placeholder in input type date element.
First of all I defined the following css:
.placeholder {
color: $text-grey;
}
input[type='date']::before {
content: attr(placeholder);
}
input::-webkit-input-placeholder {
color: $text-grey;
}
The reason why this is neccessary is that if css3 content has different color that the normal placeholder, so I had to use a common one.
<input #birthDate
class="birthDate placeholder"
type="date"
formControlName="birthDate"
placeholder="{{getBirthDatePlaceholder() | translate}}"
[class.error]="!onboardingForm.controls.birthDate.valid && onboardingForm.controls.birthDate.dirty"
autocomplete="off"
>
Then in the template used a viewchild birthDate attribute, to be able to access this input from the component. And defined an angular expression on the placeholder attribute, which will decide if we show the placeholder or not. This is the major drawback of the solution, is that you have to manage the visibility of the placeholder.
@ViewChild('birthDate') birthDate;
getBirthDatePlaceholder() {
if (!this.birthDate) {
return;
} else {
return this.birthDate.nativeElement.value === '' ?
'ONBOARDING_FORM_COMPONENT.HINT_BIRTH_DATE' :
'';
}
}
Expanding on @mvp's solution with unobtrusive javascript in mind, here's the approach:
HTML:
<input type="text" placeholder="Date" class="js-text-date-toggle">
Javascript:
$('.js-text-date-toggle').on('focus', function() {
$(this).attr('type', 'date') }
).on('blur', function() {
$(this).attr('type'), 'text') }
)
According to the HTML standard:
The following content attributes must not be specified and do not apply to the element: accept, alt, checked, dirname, formaction, formenctype, formmethod, formnovalidate, formtarget, height, inputmode, maxlength, minlength, multiple, pattern, placeholder, size, src, and width.
I ended up using the following.
Regarding Firefox comment(s): Generally, Firefox will not show any text placeholder for inputs type date. But as this is a Cordova/PhoneGap question this should be of no concern (Unless you want to develop against FirefoxOS).
input[type="date"]:not(.has-value):before{_x000D_
color: lightgray;_x000D_
content: attr(placeholder);_x000D_
}
_x000D_
<input type="date" placeholder="MY PLACEHOLDER" onchange="this.className=(this.value!=''?'has-value':'')">
_x000D_
If you use mvp's method but add the onblur event to change it back to a text field so the placeholder text appears again when the input field looses focus. It just makes the hack a little bit nicer.
<input placeholder="Date" class="textbox-n" type="text" onfocus="(this.type='date')" onblur="(this.type='text')" id="date" />
_x000D_
Hope this helps.
I used this in my css:
input[type="date"]:before{
color:lightgray;
content:attr(placeholder);
}
input[type="date"].full:before {
color:black;
content:""!important;
}
and put somenthing like this into javascript:
$("#myel").on("input",function(){
if($(this).val().length>0){
$(this).addClass("full");
}
else{
$(this).removeClass("full");
}
});
it works for me for mobile devices (Ios8 and android). But I used jquery inputmask for desktop with input text type. This solution it's a nice way if your code run on ie8.
Adressing the problem in the current correct answer "clicking the field shows the onscreen keyboard instead of the datepicker":
The problem is caused by the Browser behaving according to the type of input when clicking (=text). Therefore it is necessary to stop from focussing on the input element (blur) and then restart focus programmatically on the input element which was defined as type=date by JS in the first step. Keyboard displays in phonenumber-mode.
<input placeholder="Date" type="text" onfocus="this.type='date';
this.setAttribute('onfocus','');this.blur();this.focus();">
I think all you have to do is change the model to say the date field is nullable and then put [Required] on it if it is required. If you do this the placeholder text does appear.
Found a better way to solve your problem. I think this will help you. when focused out, the box will change type into text so it will show your placeholder. when focused in, its type changes into date so the calendar view will be shown.
<input placeholder="Date" class="textbox-n" type="text" onfocusin="(this.type='date')" onfocusout="(this.type='text')" id="date">
Hey so I ran into the same issue last night and figured out a combination of all of your answer and some sparkling magic are doing a good job:
The HTML:
<input type="date" name="flb5" placeholder="Datum" class="datePickerPlaceHolder"/>
The CSS:
@media(max-width: 1024px) {
input.datePickerPlaceHolder:before {
color: #A5A5A5; //here you have to match the placeholder color of other inputs
content: attr(placeholder) !important;
}
}
The jQuery:
$(document).ready(function() {
$('input[type="date"]').change(function(){
if($(this).val().length < 1) {
$(this).addClass('datePickerPlaceHolder');
} else {
$(this).removeClass('datePickerPlaceHolder');
}
});
});
Explanation: So, what is happening here, first of all in the HTML, this is pretty straight forward just doing a basic HMTL5-date-input and set a placeholder. Next stop: CSS, we are setting a :before-pseudo-element to fake our placeholder, it just takes the placeholder's attribute from the input itself. I made this only available down from a viewport width of 1024px - why im going to tell later. And now the jQuery, after refactoring a couple of times I came up with this bit of code which will check on every change if there is a value set or not, if its not it will (re-)add the class, vice-versa.
KNOW ISSUES:
hope that helps! cheerio!
try my solution. I use 'required' attribute to get know whether input is filled and if not I show the text from attribute 'placeholder'
//HTML
<input required placeholder="Date" class="textbox-n" type="date" id="date">
//CSS
input[type="date"]:not(:valid):before {
content: attr(placeholder);
// style it like it real placeholder
}
HTML:
<div>
<input class="ui-btn ui-btn-icon-right ui-corner-all ui-icon-calendar ui-shadow" id="inputDate" type="date"/>
<h3 id="placeholder-inputDate">Date Text</h3>
</div>
JavaScript:
$('#inputDate').ready(function () {
$('#placeholder-inputDate').attr('style'
, 'top: ' + ($('#placeholder-inputDate').parent().position().top + 10)
+ 'px; left: ' + ($('#placeholder-inputDate').parent().position().left + 0) + 'px; position: absolute;');
$('#inputDate').attr('style'
, 'width: ' + ($('#placeholder-inputDate').width() + 32) + 'px;');
});
If you're only concerned with mobile:
input[type="date"]:invalid:before{
color: rgb(117, 117, 117);
content: attr(placeholder);
}
I used this whit jQuery: http://jsfiddle.net/daviderussoabram/65w1qhLz/
$('input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="month"], input[type="time"], input[type="week"]').each(function() {
var el = this, type = $(el).attr('type');
if ($(el).val() == '') $(el).attr('type', 'text');
$(el).focus(function() {
$(el).attr('type', type);
el.click();
});
$(el).blur(function() {
if ($(el).val() == '') $(el).attr('type', 'text');
});
});
SO what i have decided to do finally is here and its working fine on all mobile browsers including iPhones and Androids.
$(document).ready(function(){_x000D_
_x000D_
$('input[type="date"]').each(function(e) {_x000D_
var $el = $(this), _x000D_
$this_placeholder = $(this).closest('label').find('.custom-placeholder');_x000D_
$el.on('change',function(){_x000D_
if($el.val()){_x000D_
$this_placeholder.text('');_x000D_
}else {_x000D_
$this_placeholder.text($el.attr('placeholder'));_x000D_
}_x000D_
});_x000D_
});_x000D_
_x000D_
});
_x000D_
label {_x000D_
position: relative; _x000D_
}_x000D_
.custom-placeholder {_x000D_
#font > .proxima-nova-light(26px,40px);_x000D_
position: absolute;_x000D_
top: 0;_x000D_
left: 0;_x000D_
z-index: 10;_x000D_
color: #999;_x000D_
}
_x000D_
<label>_x000D_
<input type="date" placeholder="Date">_x000D_
<span class="custom-placeholder">Date</span>_x000D_
</label>
_x000D_
Date
To summarize the date inputs problem:
The solution I found to meet those requirements is to use the usual trick to style native form elements : ensure the element is displayed but not visible, and display its expected style through its associated label. Typically, the label will display as the input (including a placeholder), but over it.
So, an HTML like:
<div class="date-input>
<input id="myInput" type="date">
<label for="myInput">
<span class="place-holder">Enter a date</span>
</label>
</div>
Could be styled as:
.date-input {
display: inline-block;
position: relative;
}
/* Fields overriding */
input[type=date] + label {
position: absolute; /* Same origin as the input, to display over it */
background: white; /* Opaque background to hide the input behind */
left: 0; /* Start at same x coordinate */
}
/* Common input styling */
input[type=date], label {
/* Must share same size to display properly (focus, etc.) */
width: 15em;
height: 1em;
font-size: 1em;
}
Any event (click, focus) on such an associated label will be reflected on the field itself, and so trigger the date input UI.
Should you want to test such a solution live, you can run this Angular version from your tablet or mobile.
It works for me:
input[type='date']:after {
content: attr(placeholder)
}
Here is another possible hack not using js and still using css content
. Note that as :after
is not supported on some browser for inputs, we need to select the input in another way, same for content attr('')
input[type=date]:invalid+span:after {_x000D_
content:"Birthday";_x000D_
position:absolute;_x000D_
left:0;_x000D_
top:0;_x000D_
}_x000D_
_x000D_
input[type=date]:focus:invalid+span:after {_x000D_
display:none;_x000D_
}_x000D_
_x000D_
input:not(:focus):invalid {_x000D_
color:transparent;_x000D_
}_x000D_
_x000D_
label.wrapper {_x000D_
position:relative;_x000D_
}
_x000D_
<label class="wrapper">_x000D_
<input_x000D_
type="date"_x000D_
required="required" _x000D_
/>_x000D_
<span></span>_x000D_
</label>
_x000D_
You can
like this...
$("#dateplaceholder").change(function(evt) {_x000D_
var date = new Date($("#dateplaceholder").val());_x000D_
$("#dateplaceholder").attr("type", "text");_x000D_
$("#dateplaceholder").val(date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear());_x000D_
});_x000D_
$("#dateplaceholder").focus(function(evt) {_x000D_
$("#dateplaceholder").attr("type", "date");_x000D_
setTimeout('$("#dateplaceholder").click();', 500);_x000D_
});_x000D_
$("#dateplaceholder").attr("type", "text");
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>_x000D_
<input type="date" id="dateplaceholder" placeholder="Set the date" />
_x000D_
Found a better way to handle user basic comprehension with mouseover and opening datepicker on click :
<input type="text" onfocus="(this.type='date')" onmouseover="(this.type = 'date')" onblur="(this.value ? this.type = 'date' : this.type = 'text')" id="date_start" placeholder="Date">
Also hide webkit arrow and make it 100% wide to cover the click :
input[type="date"] {
position: relative;
}
input[type="date"]::-webkit-calendar-picker-indicator {
position: absolute;
height: 100%;
width: 100%;
opacity: 0;
left: 0;
right: 0;
top:0;
bottom: 0;
}
Took me a while figuring this one out, leave it as type="text"
, and add onfocus="(this.type='date')"
, just as shown above.
I even like the onBlur idea mentioned above
<input placeholder="Date" class="textbox-n" type="text" onfocus="(this.type='date')" onblur="(this.type='text')" id="date">
Hope this helps anyone who didn't quite gather whats going on above
As of today (2016), I have successfully used those 2 snippets (plus they work great with Bootstrap4).
input[type=date] {
text-align: right;
}
input[type="date"]:before {
color: lightgrey;
content: attr(placeholder) !important;
margin-right: 0.5em;
}
input[type="date"]:before {
color: lightgrey;
content: attr(placeholder) !important;
margin-right: 0.5em;
}
input[type="date"]:focus:before {
content: '' !important;
}
Based on deadproxor and Alessio answers, I would try only using CSS:
input[type="date"]::before{
color: #999;
content: attr(placeholder) ": ";
}
input[type="date"]:focus::before {
content: "" !important;
}
And if you need to make the placeholder invisible after writing something in the input, we could try using the :valid and :invalid selectors, if your input is a required one.
EDIT
Here the code if you are using required in your input:
input[type="date"]::before {_x000D_
color: #999999;_x000D_
content: attr(placeholder);_x000D_
}_x000D_
input[type="date"] {_x000D_
color: #ffffff;_x000D_
}_x000D_
input[type="date"]:focus,_x000D_
input[type="date"]:valid {_x000D_
color: #666666;_x000D_
}_x000D_
input[type="date"]:focus::before,_x000D_
input[type="date"]:valid::before {_x000D_
content: "" !important;_x000D_
}
_x000D_
<input type="date" placeholder="Date" required>
_x000D_
This works for me using this as input element:
<input name="birthdate" class="" class="wpcf7-form-control wpcf7-date
wpcf7-validates-as-required wpcf7-validates-as-date birthdate" value=""
aria-required="true" aria-invalid="false" placeholder="birthdate *"
type="date">
This CSS shows a permanent placeholder. The selected value is shown after the placeholder.
input[type="date"]:before {
content: attr(placeholder) !important;
margin-right: 0.5em;
display: block;
}
/* only for FF */
@-moz-document url-prefix() {
input[type="date"]:before {
content: attr(placeholder) !important;
margin-right: 0.5em;
display: block;
position: absolute;
left: 200px; /* please adopt */
}
}
I use this solution for a Wordpress form with contact-form-7 plugin.
Extension of Mumthezir's version that works better on iOS, based on Mathijs Segers' comment:
(Uses some AngularJS but hopefully you get the idea.)
<label style='position:relative'>
<input type="date"
name="dateField"
onfocus="(this.type='date')"
ng-focus="dateFocus=true" ng-blur="dateFocus=false" />
<span ng-if='!dateFocus && !form.date' class='date-placeholder'>
Enter date
</span>
</label>
Because it's all wrapped in a label
, clicking the span
automatically focuses the input
.
CSS:
.date-placeholder {
display: inline-block;
position: absolute;
text-align: left;
color: #aaa;
background-color: white;
cursor: text;
/* Customize this stuff based on your styles */
top: 4px;
left: 4px;
right: 4px;
bottom: 4px;
line-height: 32px;
padding-left: 12px;
}
<input placeholder="Date" type="text" onMouseOver="(this.type='date')" onMouseOut="(this.type='text')" id="date" class="form-control">
_x000D_
Revised code of mumthezir
You could use the "value" attribute, for example:
<input type="date" value="Date" class="textbox-n" id="date"/>
None of the solutions were working correctly for me on Chrome in iOS 12 and most of them are not tailored to cope with possible multiple date inputs on a page. I did the following, which basically creates a fake label over the date input and removes it on tap. I am also removing the fake label if viewport width is beyond 992px.
JS:
function addMobileDatePlaceholder() {
if (window.matchMedia("(min-width: 992px)").matches) {
$('input[type="date"]').next("span.date-label").remove();
return false;
}
$('input[type="date"]').after('<span class="date-label" />');
$('span.date-label').each(function() {
var $placeholderText = $(this).prev('input[type="date"]').attr('placeholder');
$(this).text($placeholderText);
});
$('input[type="date"]').on("click", function() {
$(this).next("span.date-label").remove();
});
}
CSS:
@media (max-width: 991px) {
input[type="date"] {
padding-left: calc(50% - 45px);
}
span.date-label {
pointer-events: none;
position: absolute;
top: 2px;
left: 50%;
transform: translateX(-50%);
text-align: center;
height: 27px;
width: 70%;
padding-top: 5px;
}
}
Source: Stackoverflow.com