DEV Community

Cover image for Giving an HTML date input a placeholder with JavaScript
Grant Collins
Grant Collins

Posted on

Giving an HTML date input a placeholder with JavaScript

I've been building a to-do list web app as part of The Odin Project's JavaScript course. The user actions are basic: add and delete tasks and projects, as well as edit tasks. But in coding a way for a user to edit a task, I came across a problem.

When a task card is clicked in the app, a full-screen pop-up with a form appears where a user can edit that specific task's details (i.e., name, description, project, priority, and due date). So, all that task's currently selected info should be presented as editable content within the form, or as placeholder values in the inputs.

While giving placeholders to the first four of these inputs is fairly straightforward—using a placeholder attribute on the first two type="text" inputs and setting the selected attribute on the last two option inputs to true for the correct option—I couldn't figure out a way to display the task's previously selected due date as a placeholder on a type="date" input. Instead, the default mm/dd/yyyy remained as the "placeholder" for my date input, even if I gave this input a placeholder attribute with a value.

Off to Google I went, quickly discovering this is a known problem and coming across this Stack Overflow threadand this GeeksforGeeks article.

Solution 1: CSS's ::before pseudo-element

The top-voted comment in the SO thread suggests using the ::before pseudo-element in CSS to create a placeholder before the mm/dd/yyyy default, but that still appears as if its within the date input field.

<input type="date" placeholder="Choose a Date" />
Enter fullscreen mode Exit fullscreen mode
  input[type="date"]:before {
    content: attr(placeholder) !important;
    color: #aaa;
    margin-right: 0.5em;
  }
  input[type="date"]:focus:before,
  input[type="date"]:valid:before {
    content: "";
  }
Enter fullscreen mode Exit fullscreen mode

When the input field is selected, the placeholder goes away and a user is just left with the option to select a date.

While this seems to be a fine method (although it doesn't appear to work on Firefox) in certain situations, it isn't what I was looking for. I needed the input to display just task's current date as a placeholder, not also the default mm/dd/yyyy.

Solution 2: The onfocus attribute

The GeeksforGeeks article and the second top-rated SO comment recommend an alternate approach: writing the input as a standard type='text' input and giving it the placeholder value you want. Then, using the onfocus attribute, the input can (ideally) change to type='date' input, like so:

<input type="date" placeholder="01/01/2001" onfocus="(this.type='date')">
Enter fullscreen mode Exit fullscreen mode

Unfortunately, to reasons unknown to me I couldn't get this to work. I tested it in multiple browsers, and still got nothing.

So, I chose to figure out a different method to give my date input a placeholder.

Solution 3: A button and an event listener

The approach I came up with, while perhaps not the cleanest solution, works fine for what I needed.

My code is pasted below as well as here in a CodePen if you want to play around with it on your own.

<button id="date-input-btn">01/01/2001</button>
Enter fullscreen mode Exit fullscreen mode
#date-input-btn, #date-input {
    outline: none;
    border: none;
    font-family: Helvetica;
    font-size: 16px;
    border-radius: 4px;
    font-weight: 500;
    background-color: lightgray;
    color: gray;
}

#date-input-btn {
  padding: 5px 6px;
  text-align: left;
}

#date-input {
   padding: 4px 6px;
}
Enter fullscreen mode Exit fullscreen mode
function switchToDateInput() {
  document.getElementById('date-input-btn').remove(); 

  const dateInput = document.createElement('input');
  dateInput.type = 'date';
  dateInput.id = 'date-input';

  document.body.appendChild(dateInput);
}

const dateInputBtn = document.getElementById('date-input-btn');
dateInputBtn.addEventListener('click', switchToDateInput);
}
Enter fullscreen mode Exit fullscreen mode

The code in my to-do list project is slightly more complicated, as I am creating all the DOM elements with JS and appending the button and input to a different div container element, but the idea is the same as in the code above.

What's going on here?

In my HTML file I have a button element with an id of #date-input-btn. The text inside this button simulates the placeholder value for my date input.

In the JS file, I have an event listener on the button that, when clicked, triggers a function called switchToDateInput(). All this function does is remove the button that was clicked and append a date input to the DOM in its place, giving the appearance that the button "transformed" into a date input when clicked.

Finally, if we just style both our button and date input the same, we get a simulated placeholder value for a date input!

Note: I added one extra pixel to the top and bottom padding on the button. In my case this made the button appear as the same height as the date input that takes its place.

Here's the final result from my CodePen using the code above:

Before click:

date input button before clicking

After click:

date input after clicking

One downside of this approach is that a user has to click twice—once to fire the event listener on the button and a second time to bring up the date input selector.

If you're curious, here's what this looks like in my to-do list project:

Before click:

date input button in my to-do list project before clicking

After click:

date input in my to-do list project after clicking

Conclusion

I hope this helps if you've encountered this same problem of wanting to give a date input a "pre-selected" date as a placeholder. If you know of a more elegant solution (or if you figure out what I did wrong with solution 2), I'd love to hear it.

Thanks for reading and carry on coding.

Top comments (1)

Collapse
 
messenja profile image
Dmitry • Edited

That works for me (i use react, but it doesnt matter):

const { id, placeHolder } = props;

const handleFocus = (event: React.ChangeEvent<HTMLInputElement>) => {
    event.target.type = 'date';
  };

const handleBlur = (event: React.ChangeEvent<HTMLInputElement>) => {
  if (!event.target.value) {
    event.target.type = 'text';
  }
};

...

<input
        id={id}
        name={id}
        type="text"
        placeholder={placeHolder}
        onFocus={handleFocus}
        onBlur={handleBlur}
/>
Enter fullscreen mode Exit fullscreen mode