Skip to content

Instantly share code, notes, and snippets.

@jankalfus
Last active October 7, 2020 17:51
Show Gist options
  • Save jankalfus/4a705075acf6e6235950adf4cede93e7 to your computer and use it in GitHub Desktop.
Save jankalfus/4a705075acf6e6235950adf4cede93e7 to your computer and use it in GitHub Desktop.
Text area with auto height component for React
import React, {
TextareaHTMLAttributes,
useCallback,
useEffect,
useRef,
} from "react";
export function AutoHeightTextarea({
minRows = 1,
...props
}: TextareaHTMLAttributes<HTMLTextAreaElement> & { minRows?: number }) {
const ref = useRef<HTMLTextAreaElement>(null);
const calculateAndSetHeight = useCallback(() => {
if (!ref.current) {
return;
}
const {
borderBottomWidth,
borderTopWidth,
boxSizing,
lineHeight,
paddingBottom,
paddingTop,
} = window.getComputedStyle(ref.current);
ref.current.style.height = lineHeight; // set height temporarily to a single row to obtain scrollHeight, disregarding empty space after text (otherwise, scrollHeight would be equal to the height of the element) - this solves auto-shrinking of the textarea (it's not needed for auto-growing it)
const { scrollHeight } = ref.current; // scrollHeight = content height + padding top + padding bottom
if (boxSizing === "border-box") {
const minHeight =
parseFloat(lineHeight) * minRows +
parseFloat(paddingTop) +
parseFloat(paddingBottom) +
parseFloat(borderTopWidth) +
parseFloat(borderBottomWidth);
const allTextHeight =
scrollHeight +
parseFloat(borderTopWidth) +
parseFloat(borderBottomWidth);
ref.current.style.height = `${Math.max(minHeight, allTextHeight)}px`;
} else if (boxSizing === "content-box") {
const minHeight = parseFloat(lineHeight) * minRows;
const allTextHeight =
scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom);
ref.current.style.height = `${Math.max(minHeight, allTextHeight)}px`;
} else {
console.error("Unknown box-sizing value.");
}
}, [minRows]);
useEffect(() => {
calculateAndSetHeight();
}, [calculateAndSetHeight]);
function handleChange() {
calculateAndSetHeight();
}
return <textarea {...props} onChange={handleChange} ref={ref} />;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment