Home > Mobile >  Set height of textarea based on value with onInput or onChange?
Set height of textarea based on value with onInput or onChange?

Time:12-28

I'm using this example to set the height of the textarea.

but the size of the textarea is not set automatically if the textarea has a value.

https://codesandbox.io/s/autosize-textarea-forked-wdowvr?file=/src/App.tsx

import { useRef, useState } from "react";

import "./styles.css";

export default function App() {
  const [value, setValue] = useState("");
  const textAreaRef = useRef<HTMLTextAreaElement>(null);

  const handleChange = (evt) => {
    const val = evt.target?.value;

    setValue(val);
  };

  return (
    <div className="App">
      <label htmlFor="review-text">Review:</label>
      <textarea
        id="review-text"
        onChange={handleChange}
        onInput={(e: React.FormEvent<HTMLTextAreaElement>) => {
          e.currentTarget.style.height = e.currentTarget.scrollHeight   "px";
        }}
        ref={textAreaRef}
        rows={1}
        value={value}
      />
    </div>
  );
}

for example

how can i fix this issue?

CodePudding user response:

You can use the following snippets to adjust the height on loading the component.

Just for demo purposes:

const [value, setValue] = useState(
  "already has a value with\nmore text\nand even more"
);
const textAreaRef = useRef<HTMLTextAreaElement>(null);

You can access the ref once it is set. useEffect will do the trick here.

useEffect(() => {
  if (textAreaRef && textAreaRef.current) {
    textAreaRef.current.style.height = textAreaRef.current.scrollHeight   'px';
  }
}, []);

https://codesandbox.io/s/autosize-textarea-forked-symr7p?file=/src/App.tsx

CodePudding user response:

You also need to set the height initially once. This way it can respond to whatever value is in there without any user input.
I do this with the useEffect hook (don't forget to import it from react).

I also tweaked the method of changing the height a bit, because it wasn't working properly.

import { useRef, useState, useEffect } from "react";

import "./styles.css";

export default function App() {
  const [value, setValue] = useState("");
  const textAreaRef = useRef<HTMLTextAreaElement>(null);

  const handleChange = (evt) => {
    const val = evt.target?.value;

    setValue(val);
  };

  const resizeTextarea = (t: HTMLTextAreaElement) => {
    t.style.height = "auto";
    const p = parseFloat(window.getComputedStyle(t, null).getPropertyValue("padding-top")) 
              parseFloat(window.getComputedStyle(t, null).getPropertyValue("padding-bottom"));
    t.style.height = t.scrollHeight - p   "px";
  }

  const handleInput = (e: React.FormEvent<HTMLTextAreaElement>) => {
    resizeTextarea(e.currentTarget);
  }

  useEffect(() => {
    const t = textAreaRef.current;
    if (t != null) {
      t.style.overflowY = 'hidden';
      resizeTextarea(t);
    }
 });

  return (
    <div className="App">
      <label htmlFor="review-text">Review:</label>
      <textarea
        id="review-text"
        onChange={handleChange}
        onInput={handleInput}
        ref={textAreaRef}
        rows={1}
        value={value}
      />
    </div>
  );
}

https://codesandbox.io/s/autosize-textarea-forked-s39ur2?file=/src/App.tsx:0-1172

  • Related