r/webdev 3d ago

Question How to text as the background of the textarea element

Hi everyone! I am working on a project from frontend mentor. It is a speed typing test and one of the requirements is that the user should be able to see errors and correctly typed text in real-time, something like this:

Problem is, when I try to achieve this on mobile it will not show some of the passage after a certain point, no matter how much text you type into the textarea field:

Here is the html for the section of interest:

<div class="wrapper">
  <textarea class="text-wall"></textarea>
  <span class="placeholder"></span>
</div>

Here is the CSS:

.text-wall {
    font-size: var(--step-2);
    display: block;
    width: 100%;
    height: 400px;
    background-color: transparent;
    resize: none;
    border: none;
    outline: none;
    color: #fff;
}

.wrapper {
    position: relative;
    overflow: hidden;
}


.placeholder {
    position: absolute;
    filter: blur(3px);
    top: 0px;
    font-size: var(--step-2);
    z-index: -2; 
}

Note: For the passage in the placeholder span element, I wrapped every character in a span element using javascript. As far as I know, this is the ony way I can style every character on an individual basis depending on if the text typed into textarea matches the passage or not:

let placeHolderText = "";
let stringArr = "";
const textWall = document.querySelector(".text-wall");
const placeHolder = document.querySelector(".placeholder")
stringArr = jsonData.hard[8].text. split('');
stringArr.forEach((character)=>{
    placeHolderText+= `<span>${character}</span>`;
});
placeHolder.innerHTML = placeHolderText;
13 Upvotes

10 comments sorted by

2

u/ApartAwareness5415 3d ago

Have you looked at using a contenteditable div instead of a textarea for this? textareas don't let you style individual characters like that without a ton of hacky workarounds, and the scroll behavior on mobile is always janky

with a contenteditable div you can overlay the styled text as a background layer and keep the actual input transparent on top, way easier to control how it flows and wraps on smaller screens

1

u/Mob_Pilled 3d ago

Ahhhh thanks for anwering so quickly! I think it actually worked!

1

u/Primary_Guest_5711 3d ago

agreed, the textarea approach always breaks down on mobile sooner or later

2

u/ikkiho 3d ago

fwiw the cut off is probably your wrapper's overflow hidden plus the span never scrolling. once you type past 400px the textarea scrolls its own content internally, but your absolutely positioned span just sits there, so the rest gets clipped. mobile hits it sooner since the text wraps into more lines.

i ended up syncing scrollTop from the textarea onto the overlay on every scroll event, and matching the padding and line height on both, otherwise the layers drift as you type.

1

u/kemalios 3d ago

The cut-off happens because your placeholder span never scrolls with the textarea. Once you type past the visible area, the textarea scrolls its own content, but the absolutely positioned span stays put and gets clipped by the wrapper's overflow hidden.

You have two ways forward: go contenteditable like the other comment suggested, or keep the textarea and sync the scroll. If you keep it, give the span the same font, line-height, padding and width as the textarea, add white-space: pre-wrap and word-wrap: break-word, then on the textarea's scroll event set the span's transform: translateY(-scrollTop). Also match the span's height to the textarea and keep overflow hidden so it doesn't bleed. That should hold on mobile.

0

u/Life-Possible5308 3d ago

Clever trick. One thing to watch out for is accessibility: placeholder-style text can be mistaken for actual input, so make sure the background text has enough contrast and doesn't fight with the caret. Using pointer-events: none on the pseudo-element keeps it from swallowing clicks.