bgenc.net/content/posts/2023.07.02.css-only-contenteditable-placeholder.md
Kaan Barmore-Genç db46e25ed7
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Add "CSS only placeholder for contenteditable elements" post
2023-07-02 13:51:40 -05:00

2.4 KiB

title date toc images tags
CSS only placeholder for contenteditable elements 2023-07-02T13:06:15-05:00 false
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:

<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:

{{}}

{{}}

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.