---
title: "CSS only placeholder for contenteditable elements"
date: 2023-07-02T13:06:15-05:00
toc: false
images:
tags:
  - dev
  - web
---

The HTML elements `input` and `textarea` include a `placeholder` property. This
property puts a placeholder text, which then disappears once the user selects
the input and types something in. I'm sure you've seen a placeholder before, it
doesn't need much explanation.

But what if an `input` or `textarea` doesn't fit your needs? `input` only allows
a single line of text. While `textarea` does allow multiple lines, the height of
the text area is fixed. If you want it to expand as the user types, you need to
add javascript to resize it on the fly. But there is an alternative: you can use
a `div` that is marked `contenteditable`. Div's can resize based on their
contents, so this is an easy way to create a text area that resizes
automatically without any javascript.

But the downside to using an editable div is that basic functionality like
`placeholder` doesn't exist. And if you duckduckgo this, you'll find a lot of
people working around the problem with javascript. While this is certainly
possible, I am trying to minimize the amount of javascript on this page. That's
the whole reason why I didn't use a `textarea` in the first place! But I found a
way to add a placeholder to a `contenteditable` span without javascript. Here it is:

```html
<span contenteditable="true" data-placeholder="click on me and type"></span>
<style>
/* Add the placeholder text */
[data-placeholder]::before {
  content: attr(data-placeholder);
  /* Or whatever  */
  color: gray;
}
/* Hide the placeholder when selected, or when there is text inside */
[data-placeholder]:focus::before, [data-placeholder]:not(:empty)::before {
  content: none;
}
</style>
```

And here what it looks like:

{{<raw>}}
<iframe width="100%" height="300" src="//jsfiddle.net/SeriousBug/t9hmgyq5/13/embedded/result,html,css/" allowfullscreen="allowfullscreen" allowpaymentrequest frameborder="0"></iframe>
{{</raw>}}

This also works with a `div`, but there is one caveat: If the user types
something into the `div` then deletes it, the browser will leave a `<br/>` in
the `div`. This means the `div` won't be empty, and the placeholder won't come
back. Boo! The same issue doesn't happen with a `span` though, so use a `span`
that is set to `display: block` instead.

Also, remember to not only rely on just the placeholder. Make sure to add labels
to your inputs.
