Skip to main content

Introduction

TextareaAutosize is a textarea component that automatically adjusts its height to match the content. It provides a better user experience by eliminating scrollbars in most cases.
import TextareaAutosize from '@mui/material/TextareaAutosize';

Basic Usage

import * as React from 'react';
import TextareaAutosize from '@mui/material/TextareaAutosize';

export default function BasicTextareaAutosize() {
  return (
    <TextareaAutosize
      aria-label="minimum height"
      minRows={3}
      placeholder="Type something..."
      style={{ width: 200 }}
    />
  );
}

Props

minRows

  • Type: number | string
  • Default: 1
Minimum number of rows to display.
<TextareaAutosize
  minRows={4}
  placeholder="Minimum 4 rows"
/>

maxRows

  • Type: number | string
  • Default: undefined
Maximum number of rows to display. After reaching the maximum, the textarea will scroll.
<TextareaAutosize
  minRows={2}
  maxRows={6}
  placeholder="Between 2 and 6 rows"
/>

Standard Textarea Props

TextareaAutosize supports all standard HTML textarea attributes:
  • value
  • defaultValue
  • onChange
  • placeholder
  • disabled
  • readOnly
  • className
  • style
  • And more…

Controlled Component

function ControlledTextarea() {
  const [value, setValue] = React.useState('');

  return (
    <TextareaAutosize
      value={value}
      onChange={(e) => setValue(e.target.value)}
      minRows={3}
      placeholder="Controlled textarea"
      style={{ width: 300 }}
    />
  );
}

Uncontrolled Component

function UncontrolledTextarea() {
  const textareaRef = React.useRef(null);

  const handleSubmit = () => {
    console.log(textareaRef.current.value);
  };

  return (
    <div>
      <TextareaAutosize
        ref={textareaRef}
        minRows={3}
        defaultValue="Default text"
        placeholder="Uncontrolled textarea"
      />
      <button onClick={handleSubmit}>Submit</button>
    </div>
  );
}

Styling

With Inline Styles

<TextareaAutosize
  minRows={3}
  style={{
    width: '100%',
    fontSize: 16,
    fontFamily: 'Arial, sans-serif',
    padding: 12,
    borderRadius: 4,
    border: '1px solid #ccc',
  }}
/>

With CSS Classes

<TextareaAutosize
  className="custom-textarea"
  minRows={3}
/>
.custom-textarea {
  width: 100%;
  padding: 12px;
  font-size: 16px;
  border: 2px solid #1976d2;
  border-radius: 8px;
  font-family: 'Roboto', sans-serif;
}

.custom-textarea:focus {
  outline: none;
  border-color: #115293;
}

With Material-UI Styling

import { styled } from '@mui/material/styles';
import TextareaAutosize from '@mui/material/TextareaAutosize';

const StyledTextarea = styled(TextareaAutosize)(({ theme }) => ({
  width: '100%',
  fontFamily: theme.typography.fontFamily,
  fontSize: theme.typography.body1.fontSize,
  padding: theme.spacing(1.5),
  borderRadius: theme.shape.borderRadius,
  border: `1px solid ${theme.palette.divider}`,
  '&:focus': {
    outline: 'none',
    borderColor: theme.palette.primary.main,
  },
}));

function StyledExample() {
  return <StyledTextarea minRows={3} placeholder="Styled textarea" />;
}

Resize Behavior

The textarea automatically resizes based on content:
function ResizeDemo() {
  const [value, setValue] = React.useState(
    'This textarea will grow as you type more lines.\nTry adding more content!'
  );

  return (
    <TextareaAutosize
      value={value}
      onChange={(e) => setValue(e.target.value)}
      minRows={2}
      maxRows={10}
      style={{ width: 400 }}
    />
  );
}

Character Counter

function CharacterCounter() {
  const [value, setValue] = React.useState('');
  const maxLength = 200;

  return (
    <div>
      <TextareaAutosize
        value={value}
        onChange={(e) => setValue(e.target.value)}
        maxLength={maxLength}
        minRows={3}
        placeholder="Type something..."
        style={{ width: '100%' }}
      />
      <div style={{ textAlign: 'right', fontSize: 12, color: '#666' }}>
        {value.length} / {maxLength}
      </div>
    </div>
  );
}

Form Integration

function FormExample() {
  const [formData, setFormData] = React.useState({
    subject: '',
    message: '',
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Submitted:', formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="subject">Subject:</label>
        <input
          id="subject"
          type="text"
          value={formData.subject}
          onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
        />
      </div>
      <div>
        <label htmlFor="message">Message:</label>
        <TextareaAutosize
          id="message"
          value={formData.message}
          onChange={(e) => setFormData({ ...formData, message: e.target.value })}
          minRows={4}
          maxRows={10}
          placeholder="Enter your message"
          style={{ width: '100%' }}
        />
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

Validation

function ValidationExample() {
  const [value, setValue] = React.useState('');
  const [error, setError] = React.useState('');

  const handleChange = (e) => {
    const newValue = e.target.value;
    setValue(newValue);

    if (newValue.length < 10) {
      setError('Message must be at least 10 characters');
    } else if (newValue.length > 500) {
      setError('Message must not exceed 500 characters');
    } else {
      setError('');
    }
  };

  return (
    <div>
      <TextareaAutosize
        value={value}
        onChange={handleChange}
        minRows={3}
        maxRows={8}
        placeholder="Enter message (10-500 characters)"
        style={{
          width: '100%',
          borderColor: error ? 'red' : '#ccc',
        }}
      />
      {error && <div style={{ color: 'red', fontSize: 12 }}>{error}</div>}
    </div>
  );
}

Disabled State

<TextareaAutosize
  minRows={3}
  disabled
  value="This textarea is disabled"
  style={{ width: 300 }}
/>

Read-Only State

<TextareaAutosize
  minRows={3}
  readOnly
  value="This textarea is read-only"
  style={{ width: 300 }}
/>

Accessibility

Ensure proper accessibility:
<div>
  <label htmlFor="feedback-textarea">
    Feedback:
  </label>
  <TextareaAutosize
    id="feedback-textarea"
    aria-label="Feedback textarea"
    aria-describedby="feedback-help"
    minRows={3}
    placeholder="Enter your feedback"
  />
  <div id="feedback-help" style={{ fontSize: 12, color: '#666' }}>
    Please provide detailed feedback
  </div>
</div>

Performance Considerations

TextareaAutosize uses ResizeObserver when available for better performance:
// The component automatically:
// 1. Uses ResizeObserver for modern browsers
// 2. Falls back to resize event listeners
// 3. Debounces resize calculations
// 4. Cleans up listeners on unmount

<TextareaAutosize
  minRows={3}
  maxRows={10}
  // Performs well even with large content
/>

Common Patterns

Comment Box

function CommentBox() {
  const [comment, setComment] = React.useState('');

  return (
    <div style={{ border: '1px solid #ccc', borderRadius: 8, padding: 16 }}>
      <TextareaAutosize
        value={comment}
        onChange={(e) => setComment(e.target.value)}
        minRows={2}
        maxRows={6}
        placeholder="Write a comment..."
        style={{
          width: '100%',
          border: 'none',
          resize: 'none',
          outline: 'none',
          fontFamily: 'inherit',
        }}
      />
      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 8 }}>
        <button disabled={!comment.trim()}>Post Comment</button>
      </div>
    </div>
  );
}

Auto-Save

function AutoSave() {
  const [value, setValue] = React.useState('');
  const [saveStatus, setSaveStatus] = React.useState('saved');

  React.useEffect(() => {
    if (!value) return;

    setSaveStatus('saving...');
    const timer = setTimeout(() => {
      // Simulate save
      console.log('Saving:', value);
      setSaveStatus('saved');
    }, 1000);

    return () => clearTimeout(timer);
  }, [value]);

  return (
    <div>
      <TextareaAutosize
        value={value}
        onChange={(e) => setValue(e.target.value)}
        minRows={4}
        placeholder="Start typing (auto-saves)"
        style={{ width: '100%' }}
      />
      <div style={{ fontSize: 12, color: '#666' }}>{saveStatus}</div>
    </div>
  );
}

Browser Compatibility

TextareaAutosize works in all modern browsers and provides graceful degradation:
  • Chrome, Firefox, Safari, Edge: Full support
  • Older browsers: Falls back to standard textarea with manual resize

Migration from Textarea

Simple migration from standard textarea:
// Before
<textarea rows={4} />

// After
<TextareaAutosize minRows={4} />

Build docs developers (and LLMs) love