useAutoSizeTextArea

Hook que ajusta automaticamente a altura de uma textarea conforme seu conteúdo.

Visão Geral

O useAutoSizeTextArea é um hook que ajusta automaticamente a altura de uma <textarea> conforme seu conteúdo, evitando barras de rolagem e melhorando a usabilidade de campos de texto multi-linha.


Exemplo de Uso

import { useAutoSizeTextArea } from "@convertcompany/ui/hooks";
import { useRef, useState } from "react";

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

  return (
    <textarea
      ref={textAreaRef}
      value={value}
      onChange={(e) => setValue(e.target.value)}
      placeholder="Digite seu texto aqui..."
      className="w-full p-3 border rounded-md resize-none"
    />
  );
}

Parâmetros

PropriedadeTipo
textAreaRefReferência da textarea que será redimensionada automaticamente.
React.RefObject<HTMLTextAreaElement | null>
valueValor atual do campo, usado para recalcular a altura quando o conteúdo muda.
string

Comportamento

  • Ajuste automático: A altura da textarea é recalculada sempre que o value muda
  • Altura mínima: A textarea mantém sua altura mínima inicial
  • Performance: Usa useLayoutEffect para garantir que o ajuste aconteça antes da renderização
  • Sem barras de rolagem: A textarea cresce verticalmente conforme necessário

Casos de Uso

Textarea simples

import { useAutoSizeTextArea } from "@convertcompany/ui/hooks";
import { useRef, useState } from "react";

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

  return (
    <textarea
      ref={textAreaRef}
      value={value}
      onChange={(e) => setValue(e.target.value)}
      placeholder="Digite sua mensagem..."
      className="w-full p-3 border rounded-md resize-none"
    />
  );
}

Com formulário

import { useAutoSizeTextArea } from "@convertcompany/ui/hooks";
import { useRef, useState } from "react";
import { Button } from "@convertcompany/ui";

export default function FormWithTextarea() {
  const [formData, setFormData] = useState({
    title: "",
    description: ""
  });
  const textAreaRef = useRef<HTMLTextAreaElement>(null);
  
  useAutoSizeTextArea({ 
    textAreaRef, 
    value: formData.description 
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    console.log("Dados do formulário:", formData);
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div>
        <label htmlFor="title" className="block text-sm font-medium mb-2">
          Título
        </label>
        <input
          id="title"
          type="text"
          value={formData.title}
          onChange={(e) => setFormData(prev => ({ ...prev, title: e.target.value }))}
          className="w-full p-3 border rounded-md"
        />
      </div>
      
      <div>
        <label htmlFor="description" className="block text-sm font-medium mb-2">
          Descrição
        </label>
        <textarea
          ref={textAreaRef}
          id="description"
          value={formData.description}
          onChange={(e) => setFormData(prev => ({ ...prev, description: e.target.value }))}
          placeholder="Digite a descrição..."
          className="w-full p-3 border rounded-md resize-none"
          rows={3}
        />
      </div>
      
      <Button type="submit">Enviar</Button>
    </form>
  );
}

Com limite de altura máxima

import { useAutoSizeTextArea } from "@convertcompany/ui/hooks";
import { useRef, useState } from "react";

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

  return (
    <textarea
      ref={textAreaRef}
      value={value}
      onChange={(e) => setValue(e.target.value)}
      placeholder="Digite seu texto..."
      className="w-full p-3 border rounded-md resize-none max-h-32 overflow-y-auto"
      style={{ minHeight: "60px" }}
    />
  );
}

Considerações

  • Referência obrigatória: O textAreaRef deve ser uma referência válida para uma <textarea>
  • Valor reativo: O hook reage a mudanças no value, então certifique-se de passar o valor atual
  • CSS recomendado: Use resize: none para evitar conflitos com o redimensionamento manual
  • Altura inicial: Defina uma altura inicial adequada com rows ou CSS
  • Performance: O hook é otimizado para evitar re-renderizações desnecessárias

Implementação Técnica

O hook utiliza useLayoutEffect para garantir que o ajuste de altura aconteça antes da renderização visual, evitando flickering. O processo é:

  1. Reset da altura: Define height: "auto" para calcular a altura natural
  2. Cálculo da altura: Usa scrollHeight para obter a altura necessária
  3. Aplicação: Define a altura calculada no elemento
useLayoutEffect(() => {
  const textArea = textAreaRef.current;
  if (textArea) {
    textArea.style.height = "auto";
    textArea.style.height = `${textArea.scrollHeight}px`;
  }
}, [textAreaRef, value]);