Textarea

A taller input.

Dependencies

Source Code

"use client";
 
import { useEffect, useRef, useState } from "react";
import { VariantProps } from "cva";
 
import { cn } from "@/lib/utils";
 
import { composeRefs } from "@/lib/compose-refs";
import { inputStyle } from "@/components/input";
 
interface TextareaProps extends React.ComponentPropsWithRef<"textarea"> {
  invalid?: boolean;
  variant?: VariantProps<typeof inputStyle>["variant"];
}
 
const Textarea = ({ className, invalid, variant, ...props }: TextareaProps) => {
  return (
    <textarea
      data-invalid={invalid}
      aria-invalid={invalid}
      className={cn(
        inputStyle({ variant }),
        "h-auto resize-none py-2 leading-snug",
        className
      )}
      {...props}
    />
  );
};
 
// as soon as `field-sizing: content` is supported, we can remove this component and just use the Textarea
 
/**
 * A textarea that resizes as you type.
 */
const TextareaResize = ({ ref, ...props }: TextareaProps) => {
  const internalRef = useRef<HTMLTextAreaElement>(null);
  const [internalValue, setInternalValue] = useState(props.value);
 
  const value = props.value ?? internalValue;
 
  const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
    setInternalValue(event.target.value);
    props.onChange?.(event);
  };
 
  useEffect(() => {
    if (internalRef.current) {
      internalRef.current.style.height = "auto";
      internalRef.current.style.height = `${internalRef.current.scrollHeight}px`;
    }
  }, [value]);
 
  return (
    <Textarea
      ref={composeRefs(ref, internalRef)}
      {...props}
      value={value}
      onChange={handleChange}
    />
  );
};
 
export { Textarea, TextareaResize };

API Reference

Extends the textarea element.

PropDefaultType

variant

"default"

"default"

"minimal"

invalid

-

boolean

Examples

Default

Minimal

Disabled

Resizable

This is a cross-browser solution for resizing the textarea. When field-sizing: content is supported, we can remove this component and just use the Textarea.

Best Practices

  1. Sizing:

    • Consider initial height based on expected content
    • Allow resizing when appropriate
    • Maintain consistent width with other inputs
  2. Accessibility:

    • Provide clear labels
    • Consider character/word count indicators