Giving an HTML date input a placeholder with JavaScript
Tags: webdev, javascript, html, tutorial
Published: 2023-08-25 20:31:43

I've been building a to-do list web app as part of [The Odin Project](https://www.theodinproject.com/)'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 thread](https://stackoverflow.com/questions/18146350/how-do-i-simulate-placeholder-functionality-on-input-date-field)and [this GeeksforGeeks article](https://www.geeksforgeeks.org/how-to-set-placeholder-value-for-input-type-date-in-html-5/#). 

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

The top-voted comment in the SO thread suggests using the [::before](https://developer.mozilla.org/en-US/docs/Web/CSS/::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.

```html
<input type="date" placeholder="Choose a Date" />
```

```css
  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: "";
  }
```

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:

```html
<input type="date" placeholder="01/01/2001" onfocus="(this.type='date')">
```

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](https://codepen.io/grantcollins03/pen/dywYZep) in a CodePen if you want to play around with it on your own.

```HTML
<button id="date-input-btn">01/01/2001</button>
```

```CSS
#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;
}
```

```Javascript
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);
}
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8hdbk9xtfdxiyzl3mue9.png)

**After click:**

![date input after clicking](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m5p3qxj4tr20zwzj3ci8.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j71laflj52ywldy4vulc.png)

**After click:**

![date input in my to-do list project after clicking](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9uge4obc553f5no4eiu.png)

## 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.