TextArea

Multi-line text input field for longer user input.

import { TextArea } from 'ui-lab-components/textarea';
Rows4
import { TextArea } from 'ui-lab-components/textarea';
 
export default function Example() {
  return <TextArea placeholder="Enter your text here..." rows={4} />;
}
 

textarea/01-basic-textarea

TextArea with a character limit and submit button — disabled until the user types.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { TextArea } from 'ui-lab-components/textarea'
import { Flex } from 'ui-lab-components/flex'
import { Button } from 'ui-lab-components/button';
 
export default function Example() {
  const [value, setValue] = useState("");
 
  return (
    <Flex direction="column" gap="sm">
      <TextArea
        placeholder="Tell us what you think..."
        value={value}
        onChange={(e) => setValue(e.target.value)}
        showCharacterCount
        maxCharacters={300}
        rows={4}
      />
      <Button variant="primary" disabled={value.trim().length === 0} className="self-end">
        Submit
      </Button>
    </Flex>
  );
}
 

textarea/02-bio-settings

Fixed-height settings textarea with a 160-character cap and save/clear actions.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { TextArea } from 'ui-lab-components/textarea'
import { Flex } from 'ui-lab-components/flex'
import { Button } from 'ui-lab-components/button';
 
export default function Example() {
  const [bio, setBio] = useState("UI designer & developer building minimal tools.");
 
  return (
    <Flex direction="column" gap="sm">
      <TextArea
        value={bio}
        onChange={(e) => setBio(e.target.value)}
        showCharacterCount
        maxCharacters={160}
        rows={3}
        resize="none"
      />
      <Flex justify-end gap="sm">
        <Button size="sm" variant="ghost" onClick={() => setBio("")}>Clear</Button>
        <Button size="sm" variant="primary">Save</Button>
      </Flex>
    </Flex>
  );
}
 

textarea/03-error-state

Error styling triggered when the input is non-empty but below a minimum length.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { TextArea } from 'ui-lab-components/textarea'
import { Flex } from 'ui-lab-components/flex';
 
export default function Example() {
  const [value, setValue] = useState("");
  const hasError = value.trim().length > 0 && value.trim().length < 20;
 
  return (
    <Flex direction="column" gap="sm">
      <TextArea
        placeholder="Describe the issue in detail..."
        value={value}
        onChange={(e) => setValue(e.target.value)}
        error={hasError}
        rows={4}
      />
      {hasError && (
        <span style={{ fontSize: "0.75rem", var(--color-destructive)" }}>
          Description must be at least 20 characters.
        </span>
      )}
    </Flex>
  );
}
 

textarea/04-disabled-readonly

Side-by-side disabled and read-only states to compare their visual treatment.

Loading interactive preview
import { TextArea } from 'ui-lab-components/textarea'
import { Flex } from 'ui-lab-components/flex';
 
export default function Example() {
  return (
    <Flex direction="column" gap="md">
      <TextArea
        value="This field is disabled and cannot be edited."
        disabled
        rows={2}
        resize="none"
      />
      <TextArea
        value="This is a read-only note visible to all team members."
        readOnly
        rows={2}
        resize="none"
      />
    </Flex>
  );
}
 

textarea/05-scrolling

TextArea bounded by a max height — content scrolls once it overflows.

Loading interactive preview
"use client";
 
import { useState } from 'react';
import { TextArea } from 'ui-lab-components/textarea'
import { Flex } from 'ui-lab-components/flex';
 
export default function Example() {
  const [value, setValue] = useState(
    "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8"
  );
 
  return (
    <Flex direction="column" gap="sm">
      <TextArea
        value={value}
        onChange={(e) => setValue(e.target.value)}
        maxHeight="120px"
        resize="none"
      />
    </Flex>
  );
}