Kaan Barmore-Genç
db46e25ed7
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
61 lines
2.4 KiB
Markdown
61 lines
2.4 KiB
Markdown
---
|
|
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.
|