Delay HTML5 :invalid pseudo-class until the first event - html
I recently discovered that the :invalid pseudo-class applies to required form elements as soon as the page loads. For example, if you have this code:
<style>
input:invalid { background-color: pink; color: white; }
input:valid { background-color: white; color: black; }
</style>
…
<input name="foo" required />
Then your page will load with an empty pink input element on it. Having validation built in to HTML5 is great, but I don't think most users expect the form to validate before they've had a chance to enter any values at all. Is there any way to delay the application of the pseudo-class until the first event affecting that element (form submit, blur, change, whatever's appropriate)? Is it possible to do this without JavaScript?
http://www.alistapart.com/articles/forward-thinking-form-validation/
Since we only want to denote that a field is invalid once it has
focus, we use the focus pseudo-class to trigger the invalid styling.
(Naturally, flagging all required fields as invalid from the start
would be a poor design choice.)
Following this logic, your code would look something like this...
<style>
input:focus:required:invalid {background-color: pink; color: white;}
input:required:valid {background-color: white; color: black; }
</style>
Created a fiddle here: http://jsfiddle.net/tbERP/
As you'd guess, and as you'll see from the fiddle, this technique only shows the validation styling when the element has focus. As soon as you move focus off, the styling is dropped, regardless of whether it is valid or not. Not ideal by any means.
These answers are out of date. Now you can do this by checking for a placeholder pseudo-class with CSS.
input:not(:placeholder-shown):invalid {
background-color: salmon;
}
form:invalid button {
background-color: salmon;
pointer-events: none;
}
<form>
<input type="email" placeholder="me#example.com" required>
<button type="submit">Submit</button>
</form>
It starts with a normal background and turns pink as you enter you incomplete email address into it.
This is not possible in pure CSS, but can be done with JavaScript. This is a jQuery example:
// use $.fn.one here to fire the event only once.
$(':required').one('blur keydown', function() {
console.log('touched', this);
$(this).addClass('touched');
});
/**
* All required inputs initially are yellow.
*/
:required {
background-color: lightyellow;
}
/**
* If a required input has been touched and is valid, it should be white.
*/
.touched:required:valid {
background-color: white;
}
/**
* If a required input has been touched and is invalid, it should be pink.
*/
.touched:required:invalid {
background-color: pink;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
<label>
Name:
<input type="text" required> *required
</label>
</p>
<p>
<label>Age:
<input type="text">
</label>
</p>
This is a VanillaJS (no jQuery) version of kzh's answer
{
let f = function() {
this.classList.add('touched')
}
document
.querySelectorAll('input')
.forEach((e) => {
e.addEventListener('blur', f, false)
e.addEventListener('keydown', f, false)
})
}
/**
* All required inputs initially are yellow.
*/
:required {
background-color: lightyellow;
}
/**
* If a required input has been touched and is valid, it should be white.
*/
.touched:required:valid {
background-color: white;
}
/**
* If a required input has been touched and is invalid, it should be pink.
*/
.touched:required:invalid {
background-color: pink;
}
<p><label>
Name:
<input type="text" required> *required
</label></p>
<p><label>Age:
<input type="text">
</label></p>
Mozilla takes care of this with its own :-moz-ui-invalid pseudoclass that only applies to forms after they've been interacted with. MDN does not recommend using this due to a lack of support. However, you can modify it for Firefox.
There's a level 4 spec for a :user-invalid spec on the horizon that will offer similar behavior.
I created a small shim to deal with this in my codebase. I just start off with my <form/> element having the novalidate property along with a data-validate-on="blur" attribute. This watches for the first event of that type. This way you can still use the native :invalid css selectors for the form styling.
$(function () {
$('[data-validate-on]').each(function () {
var $form = $(this);
var event_name = $form.data('validate-on');
$form.one(event_name, ':input', function (event) {
$form.removeAttr('novalidate');
});
});
});
There is a html5 invalid event that fires on form elements before the submit event occurs for each element that does not pass checkValidity. You can use this event to apply a class for example to the surrounding form and display :invalid styles only after this event occurs.
$("form input, form select, form textarea").on("invalid", function() {
$(this).closest('form').addClass('invalid');
});
Your CSS would then look something like this:
:invalid { box-shadow: none; }
.invalid input:invalid,
.invalid textarea:invalid,
.invalid select:invalid { border: 1px solid #A90909 !important; background-color: #EEC2C2; }
The first line removes the default styling, so form elements look neutral at page load. As soon as the invalid event fires (when a user tries to submit the form), the elements are visibly rendered invalid.
You could make it so that only elements that have a certain class on them and are required, are pink. Add an event handler to each required element that adds that class when you leave the element.
Something like:
<style>
input.touched:invalid { background-color: pink; color: white; }
input.touched:valid { background-color: white; color: black; }
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
var required = document.querySelectorAll('input:required');
for (var i = 0; i < required.length; ++i) {
(function(elem) {
function removeClass(name) {
if (elem.classList) elem.classList.remove(name);
else
elem.className = elem.className.replace(
RegExp('(^|\\s)\\s*' + name + '(?:\\s+|$)'),
function (match, leading) {return leading;}
);
}
function addClass(name) {
removeClass(name);
if (elem.classList) elem.classList.add(name);
else elem.className += ' ' + name;
}
// If you require a class, and you use JS to add it, you end up
// not showing pink at all if JS is disabled.
// One workaround is to have the class on all your elements anyway,
// and remove it when you set up proper validation.
// The main problem with that is that without JS, you see what you're
// already seeing, and stuff looks hideous.
// Unfortunately, you kinda have to pick one or the other.
// Let non-blank elements stay "touched", if they are already,
// so other stuff can make the element :invalid if need be
if (elem.value == '') addClass('touched');
elem.addEventListener('blur', function() {
addClass('touched');
});
// Oh, and when the form submits, they need to know about everything
if (elem.form) {
elem.form.addEventListener('submit', function() {
addClass('touched');
});
};
})(required[i]);
}
});
</script>
And of course, it won't work as is in IE8 or below, as (a) DOMContentLoaded is relatively new and wasn't standard when IE8 came out, (b) IE8 uses attachEvent rather than the DOM-standard addEventListener, and (c) IE8 isn't going to care about :required anyway, as it doesn't technically support HTML 5.
While using HTML5 form validation, try to use the browser to detect for invalid submissions/fields, rather than re-inventing the wheel.
Listen for the invalid event to add a class of 'invalid' to your form. With the 'invalid' class added, you can go to town with styling your form using CSS3 :pseudo selectors.
For example:
// where myformid is the ID of your form
var myForm = document.forms.myformid;
var checkCustomValidity = function(field, msg) {
if('setCustomValidity' in field) {
field.setCustomValidity(msg);
} else {
field.validationMessage = msg;
}
};
var validateForm = function() {
// here, we're testing the field with an ID of 'name'
checkCustomValidity(myForm.name, '');
if(myForm.name.value.length < 4) {
checkCustomValidity(
// alerts fields error message response
myForm.name, 'Please enter a valid Full Name, here.'
);
}
};
/* here, we are handling your question above, by adding an invalid
class to the form if it returns invalid. Below, you'll notice
our attached listener for a form state of invalid */
var styleInvalidForm = function() {
myForm.className = myForm.className += ' invalid';
}
myForm.addEventListener('input', validateForm, false);
myForm.addEventListener('keyup', validateForm, false);
myForm.addEventListener('invalid', styleInvalidForm, true);
Now, simply style your form as you see fit based on the 'invalid' class we've attached.
For example:
form.invalid input:invalid,
form.invalid textarea:invalid {
background: rgba(255, 0, 0, .05);
border-color: #ff6d6d;
-webkit-box-shadow: 0 0 6px rgba(255, 0, 0, .35);
box-shadow: 0 0 6px rgba(255, 0, 0, .35);
}
A good way is to abstract :invalid, :valid with a CSS classes and then some JavaScript to check if the input field was focused or not.
CSS:
input.dirty:invalid{ color: red; }
input.dirty:valid{ color: green; }
JS:
// Function to add class to target element
function makeDirty(e){
e.target.classList.toggle('dirty');
}
// get form inputs
var inputs = document.forms[0].elements;
// bind events to all inputs
for(let input of inputs){
input.addEventListener('invalid', makeDirty);
input.addEventListener('blur', makeDirty);
input.addEventListener('valid', makeDirty);
}
DEMO
Following on from agouseh's idea, you can have a bit of javascript to tell when the submit button has been focussed, and have validation show up at that time.
The javascript will add a class (eg. submit-focussed) to the form field when the submit button is focussed or clicked, which then allows the CSS to style invalid inputs.
This follows the best practice of showing validation feedback after the user has finished filling in the fields, as according to research there is no additional benefit to showing it during the process.
document
.querySelector('input[type=submit]')
.onfocus = function() {
this
.closest('form')
.classList
.add('submit-focussed');
};
form.submit-focussed input:invalid {
border: thin solid red;
}
<form>
<label>Email <input type="email" required="" /></label>
<input type="submit" />
</form>
jQuery alternative
(function($) {
$('input[type=submit]').on('focus', function() {
$(this)
.parent('form')
.addClass('submit-focussed');
});
})(jQuery); /* WordPress compatible */
Here is my method to avoid the default styling of any unfocused input as invalid, you just have to add a simple js command onFocus to let the webpage to identify focused and unfocused inputs, so all the input will not appear in the style of invalid at first place.
<style>
input.focused:required:invalid { background-color: pink; color: white; }
input:valid { background-color: white; color: black; }
</style>
…
<input name="foo" class="notfocused" onFocus="document.activeElement.className='focused';" required />
Try it yourself below:
input.focused:required:invalid {
background-color: pink;
color: white;
}
input:required:valid {
background-color: darkseagreen;
color: black;
}
<label>At least 1 charater:</label><br />
<input type="text" name="foo" class="notfocused" onFocus="document.activeElement.className='focused';" required />
I can't comment, but to go with #Carl's very useful answer regarding using :not(:placeholder-shown). As another comment mentioned, this will still show the invalid state if you have NO placeholder (as some form designs call for).
To solve this, simply add an empty placeholder like so
<input type="text" name="username" placeholder=" " required>
Then your CSS, something like
:not(:placeholder-shown):invalid{ background-color: #ff000038; }
Worked for me!
Related
Is there a way of accessing HTML tag attribute in CSS within Shadow-DOM?
I'm creating a custom component with StencilJS and I have to made some changes of the outline when the user is using the keyboard or the mouse to navigate into the component. My component is using ShadowDOM and I want to access an HTML tag attribute from the CSS. The tag's attributes are generated with what-input (https://github.com/ten1seven/what-input) to detect keybord and mouse events. I've tried using CSS Selectors like [data-whatintent=keyboard] and html[data-whatintent=keyboard] but it didn't worked. This is my HTML tag from which I want to access data-whatintent attribute: <html dir="ltr" lang="en" data-whatinput="keyboard" data-whatintent="mouse"> <my-custom-component></my-custom-component> </html> And this is my CSS: [data-whatintent=keyboard] *:focus { outline: solid 2px #1A79C6; } I want that my CSS within the ShadowDOM can use the data-whatintent attribute's value to set styles on my component so the outline is like I want.
Supersharp's answer is correct, however it's not StencilJS code and also host-context support is flakey (doesn't work in Firefox and probably IE11). You can 'transfer' the attribute to the host element, and then use the selector from inside the host component style: TSX: private intent: String; componentWillLoad() { this.intent = document.querySelector('html').getAttribute('data-whatintent'); } hostData() { return { 'data-whatintent': this.intent }; } SCSS: :host([data-whatintent="keyboard"]) *:focus { outline: solid 2px #1A79C6; } If the data-whatintent attribute changes dynamically, make it a property of the component, and have the listener function update your component. You can optionally use the property to add/remove classes to the host for styling, although you could also continue to use the attribute selector. TSX: #Prop({ mutable: true, reflectToAtrr: true }) dataWhatintent: String; componentWillLoad() { this.dataWhatintent = document.querySelector('html').getAttribute('data-whatintent'); } hostData() { return { class: { 'data-intent-keyboard': this.dataWhatintent === 'keyboard' } }; } SCSS: :host(.data-intent-keyboard) *:focus { outline: solid 2px #1A79C6; } Document's keyboard and mouse event handler: function intentHandler(event: Event) { const intent = event instanceof KeyboardEvent ? 'keyboard' : 'mouse'; document.querySelectorAll('my-custom-component').forEach( el => el.setAttribute('data-whatintent', intent) ); }
You sould use :host-context() to apply a CSS style in a Shadow DOM depending on the context where the Custom Element is used. customElements.define( 'my-custom-component', class extends HTMLElement { constructor() { super() this.attachShadow( { mode: 'open' } ) .innerHTML = ` <style> :host-context( [data-whatinput=keyboard] ) *:focus { outline: solid 2px #1A79C6; } </style> <input value="Hello">` } } ) <html dir="ltr" lang="en" data-whatinput="keyboard" data-whatintent="mouse"> <my-custom-component></my-custom-component> </html>
Add Background color after setting content in input field
Is there any way that i could add a background color after placing a content inside an input field? Just like what happens when an autocomplete works. Thanks!
There are a few ways you could achieve this. You could make the input mandatory by adding the required attribute. Doing this means that as soon as the user enters anything into the field, it is now in the valid state and you can target it in your CSS using the :valid pseudo-class: input:valid{ background:#ff9; } <input required> Or, if you don't want to make the field mandatory and as others have suggested, you could set the new background-color when the field receives focus. To prevent it from reverting to its initial color when it loses focus, you will need to add a transition to the background, setting the transition-delay to some ridiculously high number when the input is in its normal state and resetting it to 0s when it is focused. Obviously, though, this change will occur whether or not the user actually enters anything in the field or not. input{ transition-delay:9999s; transition-property:background; } input:focus{ background:#ff9; transition-delay:0s; } <input> If neither of those options suit your needs then you will probably need to resort to using JavaScript to add or remove a class, depending on whether or not the value of the input is empty. document.querySelector("input").addEventListener("input",function(){ this.value?this.classList.add("filled"):this.classList.remove("filled"); },0); .filled{ background:#ff9; } <input>
Html First name: <input type="text" name="firstname"> Css input:focus { background-color: yellow; } Demo in JsFiddle
Here is a solution with pure javascript var input = document.getElementById("test"); input.addEventListener('input', function() { if (input.value) input.style.backgroundColor = '#90EE90'; else input.style.backgroundColor = '#fff'; }); <input id="test" type="text" value="">
Add a Css class like .myCSSClass { background-color:red; } Now using jquery on blur function you add this class $("#myTextBox").on('blur',function(){ if($("#myTextBox").val()==""){ if($("#myTextBox").hasClass("myCSSClass")){ $("#myTextBox").removeClass("myCSSClass"); } } else { $("#myTextBox").addClass("myCSSClass") } });
Using Jquery, $( "#target" ).blur(function() { $( "#target" ).css('background-color','red'); }); DEMO
How do I duplicate 'input required' functionality without sending with the form?
I would like to have the built-in functionality of having a text input (in the middle of other text inputs) be checked and flagged (i.e. the default red marquee applied around the text box) to make sure it is populated before the user clicks the form submit button, without including that value in the form submission. Basically, I don't want to send the retyped password with the form, but it of course needs to be filled in (and will be checked client-side). Is there a "simple" way to do this?
Here is a very minimal example of what you want. You can do this type of logic using JavaScript events like onblur, onfocus, onchange, etc. Here is an example showing you how you can validate that a field has a value in it. var validate = function(element) { // element is HTMLInputElement if (element.value == "") { element.className = "border-red"; } else { element.className = ""; } } .red { color: red; } .border-red { border: 2px solid red; } <form> Required: <input type="text" name="required_field" onblur="validate(this)" /> Optional: <input type="text" name="optional" /> </form>
Not showing placeholder for input type="date" field
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">
It may not be appropriate... but it helped me. What I did is start with a text input field, then change the type to a date input when the input is in focus. <input placeholder="Date" class="textbox-n" type="text" onfocus="(this.type='date')" id="date" />
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" />
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{ color: lightgray; content: attr(placeholder); } <input type="date" placeholder="MY PLACEHOLDER" onchange="this.className=(this.value!=''?'has-value':'')">
As of today (2016), I have successfully used those 2 snippets (plus they work great with Bootstrap4). Input data on the left, placeholder on the left input[type=date] { text-align: right; } input[type="date"]:before { color: lightgrey; content: attr(placeholder) !important; margin-right: 0.5em; } Placeholder disappear when clicking input[type="date"]:before { color: lightgrey; content: attr(placeholder) !important; margin-right: 0.5em; } input[type="date"]:focus:before { content: '' !important; }
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.
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 { color: #999999; content: attr(placeholder); } input[type="date"] { color: #ffffff; } input[type="date"]:focus, input[type="date"]:valid { color: #666666; } input[type="date"]:focus::before, input[type="date"]:valid::before { content: "" !important; } <input type="date" placeholder="Date" required>
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">
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.
It works for me: input[type='date']:after { 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'); }); });
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">
<input placeholder="01-01-2021" class="textbox-n" type="text" onfocus="(this.type='date')" onblur="(this.type='text')" id="date" />
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();">
To summarize the date inputs problem: You have to display them (i.e. avoid display:none) otherwise the input UI will not be triggered ; a placeholder is contradictory with them (as per the spec, and because they have to display a specific UI) ; converting them to another input type for the unfocused time do allows placeholders, but focus then triggers the wrong input UI (keyboard), at least for a small time, because focus events cannot be cancelled. inserting (before) or adding (after) content doesn't prevent the date input value to be displayed. 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.
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 }
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
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(){ $('input[type="date"]').each(function(e) { var $el = $(this), $this_placeholder = $(this).closest('label').find('.custom-placeholder'); $el.on('change',function(){ if($el.val()){ $this_placeholder.text(''); }else { $this_placeholder.text($el.attr('placeholder')); } }); }); }); label { position: relative; } .custom-placeholder { #font > .proxima-nova-light(26px,40px); position: absolute; top: 0; left: 0; z-index: 10; color: #999; } <label> <input type="date" placeholder="Date"> <span class="custom-placeholder">Date</span> </label> Date
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">
You can set it as type text convert to date on focus make click on it ...let user check date on change store the value set input to type text set text type input value to the stored value like this... $("#dateplaceholder").change(function(evt) { var date = new Date($("#dateplaceholder").val()); $("#dateplaceholder").attr("type", "text"); $("#dateplaceholder").val(date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear()); }); $("#dateplaceholder").focus(function(evt) { $("#dateplaceholder").attr("type", "date"); setTimeout('$("#dateplaceholder").click();', 500); }); $("#dateplaceholder").attr("type", "text"); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> <input type="date" id="dateplaceholder" placeholder="Set the date" />
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; }
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'); });
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.
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: there is a problem in chrome with its default date-picker, thats what the media-query is for. It will add the placeholder infront of the default 'dd.mm.yyyy'-thing. You could also set the placeholder of the date-input to 'date: ' and adjust the color incase of no value inside the input...for me this resulted in some other smaller issues so i went with just not showing it on 'bigger' screens hope that helps! cheerio!
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' : ''; } }
<input placeholder="Date" type="text" onMouseOver="(this.type='date')" onMouseOut="(this.type='text')" id="date" class="form-control"> Revised code of mumthezir
If you're only concerned with mobile: input[type="date"]:invalid:before{ color: rgb(117, 117, 117); content: attr(placeholder); }
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: // https://stackoverflow.com/a/20293441/3514976 function isMobile() { try { document.createEvent("TouchEvent"); return true; } catch(e) { return false; } } var deviceIsMobile = isMobile(); function mouseEnterListener(event) { var realDate = this.querySelector('.real-date'); // if it has a value it's already visible. if(!realDate.value) { this.querySelector('.fake-date').style.display = 'none'; realDate.style.display = 'block'; } } function mouseLeaveListener(event) { var realDate = this.querySelector('.real-date'); // hide it if it doesn't have focus (except // on mobile devices) and has no value. if((deviceIsMobile || document.activeElement !== realDate) && !realDate.value) { realDate.style.display = 'none'; this.querySelector('.fake-date').style.display = 'block'; } } function fakeFieldActionListener(event) { event.preventDefault(); this.parentElement.dispatchEvent(new Event('mouseenter')); var realDate = this.parentElement.querySelector('.real-date'); // to open the datepicker on mobile devices // I need to focus and then click on the field. realDate.focus(); realDate.click(); } var containers = document.getElementsByClassName('date-container'); for(var i = 0; i < containers.length; ++i) { var container = containers[i]; container.addEventListener('mouseenter', mouseEnterListener); container.addEventListener('mouseleave', mouseLeaveListener); var fakeDate = container.querySelector('.fake-date'); // for mobile devices, clicking (tapping) // on the fake input must show the real one. fakeDate.addEventListener('click', fakeFieldActionListener); // let's also listen to the "focus" event // in case it's selected using a keyboard. fakeDate.addEventListener('focus', fakeFieldActionListener); var realDate = container.querySelector('.real-date'); // trigger the "mouseleave" event on the // container when the value changes. realDate.addEventListener('change', function() { container.dispatchEvent(new Event('mouseleave')); }); // also trigger the "mouseleave" event on // the container when the input loses focus. realDate.addEventListener('blur', function() { container.dispatchEvent(new Event('mouseleave')); }); } .real-date { display: none; } /* a simple example of css to make them look like it's the same element */ .real-date, .fake-date { width: 200px; height: 20px; padding: 0px; } <div class="date-container"> <input type="text" class="fake-date" placeholder="Insert date"> <input type="date" class="real-date"> </div> 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.
This might help in some situation. <input type="text" id="date" onclick="this.type='date'" onblur="this.type='text'" placeholder="Date" class="textbox-n" name="myDate" />
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;'); });
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 { content:"Birthday"; position:absolute; left:0; top:0; } input[type=date]:focus:invalid+span:after { display:none; } input:not(:focus):invalid { color:transparent; } label.wrapper { position:relative; } <label class="wrapper"> <input type="date" required="required" /> <span></span> </label>
How to style readonly attribute with CSS?
I'm currently using readonly="readonly" to disable fields. I'm now trying to style the attribute using CSS. I've tried using input[readonly] { /* styling info here */ } but it is not working for some reason. I've also tried input[readonly='readonly'] { /* styling info here */ } that doesn't work either. How can I style the readonly attribute with CSS?
input[readonly] { background-color:blue; } https://curtistimson.co.uk/post/css/style-readonly-attribute-css/
Note that textarea[readonly="readonly"] works if you set readonly="readonly" in HTML but it does NOT work if you set the readOnly-attribute to true or "readonly" via JavaScript. For the CSS selector to work if you set readOnly with JavaScript you have to use the selector textarea[readonly]. Same behavior in Firefox 14 and Chrome 20. To be on the safe side, i use both selectors. textarea[readonly="readonly"], textarea[readonly] { ... }
Loads of answers here, but haven't seen the one I use: input[type="text"]:read-only { color: blue; } Note the dash in the pseudo selector. If the input is readonly="false" it'll catch that too since this selector catches the presence of readonly regardless of the value. Technically false is invalid according to specs, but the internet is not a perfect world. If you need to cover that case, you can do this: input[type="text"]:read-only:not([read-only="false"]) { color: blue; } textarea works the same way: textarea:read-only:not([read-only="false"]) { color: blue; } Keep in mind that html now supports not only type="text", but a slew of other textual types such a number, tel, email, date, time, url, etc. Each would need to be added to the selector.
To be safe you may want to use both... input[readonly], input[readonly="readonly"] { /*styling info here*/ } The readonly attribute is a "boolean attribute", which can be either blank or "readonly" (the only valid values). http://www.whatwg.org/specs/web-apps/current-work/#boolean-attribute If you are using something like jQuery's .prop('readonly', true) function, you'll end up needing [readonly], whereas if you are using .attr("readonly", "readonly") then you'll need [readonly="readonly"]. Correction: You only need to use input[readonly]. Including input[readonly="readonly"] is redundant. See https://stackoverflow.com/a/19645203/1766230
There are a few ways to do this. The first is the most widely used. It works on all major browsers. input[readonly] { background-color: #dddddd; } While the one above will select all inputs with readonly attached, this one below will select only what you desire. Make sure to replace demo with whatever input type you want. input[type="demo"]:read-only { background-color: #dddddd; } This is an alternate to the first, but it's not used a whole lot: input:read-only { background-color: #dddddd; } The :read-only selector is supported in Chrome, Opera, and Safari. Firefox uses :-moz-read-only. IE doesn't support the :read-only selector. You can also use input[readonly="readonly"], but this is pretty much the same as input[readonly], from my experience.
input[readonly], input:read-only { /* styling info here */ } Shoud cover all the cases for a readonly input field...
capitalize the first letter of Only input[readOnly] { background: red !important; } <input type="text" name="country" value="China" readonly="readonly" />
If you select the input by the id and then add the input[readonly="readonly"] tag in the css, something like: #inputID input[readonly="readonly"] { background-color: #000000; } That will not work. You have to select a parent class or id an then the input. Something like: .parentClass, #parentID input[readonly="readonly"] { background-color: #000000; } My 2 cents while waiting for new tickets at work :D
Use the following to work in all browsers: var readOnlyAttr = $('.textBoxClass').attr('readonly'); if (typeof readOnlyAttr !== 'undefined' && readOnlyAttr !== false) { $('.textBoxClass').addClass('locked'); }