So I have a textarea
<textarea>
Very long content. Very long content. Very long content.
Very long content. Very long content. Very long content.
Very long content. Very long content. Very long content.
Very long content. Very long content. Very long content.
Very long content. Very long content. Very long content.
Very long content. Very long content. Very long content.
</textarea>
and I want to make the textarea fit the text in the textarea as the user type in it with the code below
const textarea = document.querySelector('textarea')
textarea.addEventListener('keyup', () => {
textarea.style.height = `${textarea.scrollHeight}px`;
})
It works fine when the user add more text to the textarea. The problem is when the user clear the text inside and start typing again, the text area will not shrink to fit the text.
Any idea how to fix this?
try this, it should shrink the textarea when value is empty:
const textarea = document.querySelector('textarea')
textarea.addEventListener('keyup', () => {
textarea.style.height = textarea.value.length ? `${textarea.scrollHeight}px` : 'auto';
})
With this method, you can achieve what you want.
function calcHeight(value) {
let numberOfLineBreaks = (value.match(/\n/g) || []).length;
// min-height + lines x line-height + padding + border
let newHeight = 20 + numberOfLineBreaks * 20 + 12 + 2;
return newHeight;
}
let textarea = document.querySelector("textarea");
textarea.addEventListener("keyup", () => {
textarea.style.height = calcHeight(textarea.value) + "px";
});
You can also use span to create a textarea that has the result you want.
HTML:
<span class="textarea"></span>
CSS:
.textarea {
border: 1px solid #ccc;
font-family: inherit;
font-size: inherit;
padding: 1px 6px;
display: block;
width: 100%;
overflow: hidden;
resize: both;
min-height: 40px;
line-height: 20px;
}
Related
I am trying place an HTML element next to the end of the first line of a heading.
For a better understanding, I took screenshots of what it looks like for now and what it should look like.
What it looks like:
What it should look like:
As you can see, I used the ::first-line pseudo-selector to change the background of the first line of the title in red.
So far I have tried to add a ::after to the ::first-line but there are two issues. First, I did not manage to display a text content in the ::after. Second, you can't add html content to both ::before and ::after so it was pointless.
You should know that the "sunshines" are not an image but an actual html element :
<div className={css.container}>
<div className={css.shine1}></div>
<div className={css.shine2}></div>
<div className={css.shine3}></div>
</div>
.container {
position: absolute;
display: inline;
top: 20px;
right: 5px;
div {
position: absolute;
height: 5px;
border-radius: 5px;
background-color: $mainColor;
transform-origin: bottom left;
}
.shine1 {
width: 26px;
transform: rotate(-95deg) translate(20px, 5px);
}
.shine2 {
width: 32px;
transform: rotate(-45deg) translate(20px);
}
.shine3 {
width: 26px;
transform: rotate(0deg) translate(15px);
}
}
This is JSX with scss modules. But basically the same syntax as HTML/CSS.
Do you have any idea on how to do it, I guess it is possible since the css is capable to know where the end of the line is since I can change the background.
I have figured it out.
Although my solution is very "hacky", it works fine in any test case I thought about.
My solution is to create a hidden replica of the first line on top of the title with the same css properties. Once that is done I just get the width of the replica and use that value to define the left property of my sunshines.
This is the function I use to get the first line of the text :
const getFirstLine = el => {
const text = el.innerHTML;
//set the innerHTML to a character
el.innerHTML = 'a';
//get the offsetheight of the single character
const singleLineHeight = el.offsetHeight;
//split all innerHTML on spaces
const arr = text.split(' ');
//cur is the current value of the text we are testing to see if
//it exceeds the singleLineHeight when set as innerHTML
//prev is the previously tested string that did not exceed the singleLineHeight
//cur and prev start as empty strings
let cur = '';
let prev = '';
//loop through, up to array length
for (let i = 0; i < arr.length; i++) {
//examine the rest of text that is not already in previous string
const restOfText = text.substring(prev.length, text.length);
//the next space that is not at index 0
const nextIndex =
restOfText.indexOf(' ') === 0
? restOfText.substring(1, restOfText.length).indexOf(' ') + 1
: restOfText.indexOf(' ');
//the next part of the rest of the text
cur += restOfText.substring(0, nextIndex);
//set the innerHTML to the current text
el.innerHTML = cur;
//now we can check its offsetHeight
if (el.offsetHeight > singleLineHeight) {
//once offsetHeight of cur exceeds singleLineHeight
//previous is the first line of text
//set innerHTML = prev so
el.innerHTML = prev;
//we can grab the innertext
const firstLine = el.innerText;
const indexOfSecondLine = prev.lastIndexOf('<');
//reset el
el.innerHTML = text;
return firstLine;
}
//offsetheight did not exceed singleLineHeight
//so set previous = cur and loop again
//prev = cur + ' ';
prev += cur.substring(prev.length, cur.length);
}
el.innerHTML = text;
return text;
};
If you want to do the same be careful to wait for the fonts of the web page to be loaded or the width you will be getting will be wrong.
document.fonts.ready.then(function () {})
I have also managed to handle when the title has the text-align: center; property by adding a margin-left/right: auto; to the replica that I then get and add to the calculated left using this :
parseInt(window.getComputedStyle(invisibleTitle).marginLeft)
I know it is not perfect, but since there is no easy way to do that in css it is the only working way that I found.
you can do it if it's possible to separate the two lines in heading,
html:
<header>
<div>
<div class="first-line">
<p>
sample title, pretty long
<div className={css.container}>
<div className={css.shine1}></div>
<div className={css.shine2}></div>
<div className={css.shine3}></div>
</div>
</p>
</div>
<p>
that is wrapping in two lines
</p>
</div>
</header>
css :
header .first-line{
position: relative;
display: inline-block;
}
.container {
position: absolute;
display: inline;
top: 20px;
right: 5px;
}
.container div {
position: absolute;
height: 5px;
border-radius: 5px;
background-color: red;
transform-origin: bottom left;
}
.shine1 {
width: 26px;
transform: rotate(-95deg) translate(20px, 5px);
}
.shine2 {
width: 32px;
transform: rotate(-45deg) translate(20px);
}
.shine3 {
width: 26px;
transform: rotate(0deg) translate(15px);
}
I have a web page acting as input to an imbedded device and I change modes during operation.
I have the following h1 line.
<h1 id="speedlab">Speed: <span id="speedText">0</span>%</h1>
and I update it in one mode using :-
var output = document.getElementById("speedText");
vslidertmp = (100 -(Math.abs(vslidertmp-100)/2));
vslidertmp = (vslidertmp.toFixed(0));
glslider.value = vslidertmp;
output.innerHTML = (vslidertmp - 100) ;
when I change modes, I want to update the h1 line
to change the header text to "Trim:" and the speedtext content to the value of Trim .
I assume updating the speedtext is the same but how do I update the header text from Speed: to Trim: and leave the span element intact.
I can't work out the syntax for this.
I'd put the variable text into its own element, to allow for quick toggling of it when needed.
<h1 id="speedlab">
<span class="mode">Speed</span>: <span id="speedText">0</span>%
</h1>
And to change it
document.querySelector('.mode').textContent = 'Trim';
While you could replace the contents of the text node as well, without changing the HTML markup...
document.querySelector('#speedlab').childNodes[0].textContent = 'Trim: ';
Giving the mode its own element is nicer.
HTML:
header {
display: flex;
align - items: center;
/* Remove the next line if you want the span to appear next to the h1 */
justify - content: space - between;
border - bottom: 1 px solid #000;
padding: 10px 30px;
}
header {
border - bottom: 1 px solid #000; }
header > h1 { display: inline-block; }
header span { margin-left: 100px; }
<header>
<h1>Text</h1>
<span>text2</span>
</header>
I have a textarea and when I type something, for some words the color should change.
For example, if the typed text is next one: He went to the market to buy an apple
The "market" word should become green
The "apple" word should become red
This is my current code:
var str = 'market';
var value = str.includes('market');
if (value == str) {
document.getElementById("text").style.color = "green";
} else {
document.getElementById("text").style.color = "red";
}
<textarea rows="9" cols="100" id="text" onClick="changeText();"></textarea>
Unfortunately, you can't add markup inside a textarea, but here is an idea you could take as a starting approach, it comes from this link. The approach will be based on this:
The basic idea is to carefully position a <div> behind the <textarea>. Then JavaScript will be used to copy any text entered into the <textarea> to the <div>. A bit more JavaScript will make that both elements scroll as one. With everything perfectly aligned, we can add markup inside the <div> to give colors to some particular words, and we going to set text color to transparent on the <textarea>, completing the illusion.
Base Implementation:
// Initialization.
const colorMap = {"apple": "red", "market": "green", "banana": "orange"};
let textArea = document.getElementById("myTextArea");
let customArea = document.querySelector(".custom-area");
let backdrop = document.querySelector(".backdrop");
// Event listeners.
textArea.addEventListener("input", function()
{
customArea.innerHTML = applyColors(textArea.value);
});
textArea.addEventListener("scroll", function()
{
backdrop.scrollTop = textArea.scrollTop;
});
function applyColors(text)
{
let re = new RegExp(Object.keys(colorMap).join("|"), "gi");
return text.replace(re, function(m)
{
let c = colorMap[m.toLowerCase()];
return `<spam style="color:${c}">${m}</spam>`;
});
}
.backdrop, #myTextArea {
font: 12px 'Open Sans', sans-serif;
letter-spacing: 1px;
width: 300px;
height: 100px;
}
#myTextArea {
margin: 0;
position: absolute;
border-radius: 0;
background-color: transparent;
color: transparent;
caret-color: #555555;
z-index: 2;
resize: none;
}
.backdrop {
position: absolute;
z-index: 1;
border: 2px solid transparent;
overflow: auto;
pointer-events: none;
}
.custom-area {
white-space: pre-wrap;
word-wrap: break-word;
}
<div class="container">
<div class="backdrop">
<div class="custom-area">
<!-- Cloned text with colors will go here -->
</div>
</div>
<textarea id="myTextArea"></textarea>
</div>
Note this is just a base approach to understand the underlying idea. But with some work on it, maybe you can get a generalized version. For example, by now, the textarea can't be resizable. But maybe you can detect that event and rezise the backdrop dinamically.
You can style the text in the textarea as a whole, but since a textarea does not have sub-elements such as or you cannot give separate text within that textarea separate styles.
on the other hand if you had a separate div displaying a copy of the text you could in the innerHTML of the div assign
apple
to replace the word apple in the .. but the text in the textarea would remain unchanged.. possibly overlay div on top of the textarea but hidden until text is entered in the textarea. Not certain of the precise code to do that piece or if it would work. but at least it is a viable logic chain that I hope may help you find a solution.
To color a specific word from that text you must wrap that word with a html tag. But textarea doesn't support html tag.
You can do it outside of the textarea field.
I have a textarea,where user will input some text,and also have a input range,where user can increase the font size of text,I want that the width of textarea still same,but height increase depend font size to show all text,and also I want textarea don't have a scroll and resize
I did that using div,and I want the same result using textarea
I did that using div https://jsfiddle.net/Meline222/fgpedL0z/1/
I want the same result but using textarea https://jsfiddle.net/Meline222/fgpedL0z/3/ bt when i use textarea all text can't see
I tried did but all text don't show textarea
this work for div
#inputText {
width: 150px;
height: auto;
border: 1px solid;
word-wrap: break-word;
overflow:hidden;
resize: none;
}
If you want only the height to be adjusted along font size, use em unit measure.
width: 150px;
height: 2em;
Documentation about the em unit says
em: 1em is the same as the font-size of the current element.
JSFiddle Demo: https://jsfiddle.net/craigiswayne/qkn8rdxp/20/
function adjustSize(i){
var o = document.getElementById('inputText');
o.setAttribute("style","height: auto;");
var val = i.value;
o.style.fontSize = val + 'px';
var fontSize = o.style.fontSize;
o.setAttribute("style","font-size: " + fontSize + "; height: " + o.scrollHeight + "px;");
}
#inputText {
width: 150px;
height: auto;
border: 1px solid;
word-wrap: break-word;
}
<textarea name="" id="inputText">kyb u uuhhhkjh kj</textarea>
<input id="input" type="range" min="12" max="72" oninput="adjustSize(this);">
So the solution I chose to set the height of the textarea to it's scrollHeight
scrollHeight is defined by MDN docs as
The scrollHeight value is equal to the minimum height the element would require in order to fit all the content in the viewport without using a vertical scrollbar
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight
see also this post for an explanation of scrollHeight, clientHeight and offsetHeight
What is offsetHeight, clientHeight, scrollHeight?
I have a div with following properties
background: none repeat scroll 0 0 #999999;
border: 1px solid #639BBE;
height: 62px;
margin-top: 13px;
width: 135px;
width and height of this div is fixed i cannot change them , now if i enter some big text in that div it goes outside the div , i want to so something by which i can handle this , mean if the text of this div increases it automatically decrease the font size to adjust the text . No problem if i need to add some javascript nothing is restricted .
at the moment when i enter big text it's showing like this !
Thanks in advance
$.fn.HasScrollBar = function() {
//note: clientHeight= height of holder
//scrollHeight= we have content till this height
var _elm = $(this)[0];
var _hasScrollBar = false;
if ((_elm.clientHeight < _elm.scrollHeight) || (_elm.clientWidth < _elm.scrollWidth)) {
_hasScrollBar = true;
}
return _hasScrollBar;
}
use this function to find out the over flow and change the font size using jquery