Textarea

Multi-line text input field for longer user input.

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

Feedback Form

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

0 / 300 characters
"use client";
 
import { useState } from 'react';
import { TextArea, Flex, Button } from 'ui-lab-components';
 
export const metadata = {
  title: 'Feedback Form',
  description: 'TextArea with a character limit and submit button — disabled until the user types.'
};
 
export default function Example() {
  const [value, setValue] = useState("");
 
  return (
    <Flex direction="column" gap="sm" style={{ width: 380 }}>
      <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>
  );
}
 

Profile Bio

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

47 / 160 characters
"use client";
 
import { useState } from 'react';
import { TextArea, Flex, Button } from 'ui-lab-components';
 
export const metadata = {
  title: 'Profile Bio',
  description: 'Fixed-height settings textarea with a 160-character cap and save/clear actions.'
};
 
export default function Example() {
  const [bio, setBio] = useState("UI designer & developer building minimal tools.");
 
  return (
    <Flex direction="column" gap="sm" style={{ width: 380 }}>
      <TextArea
        value={bio}
        onChange={(e) => setBio(e.target.value)}
        showCharacterCount
        maxCharacters={160}
        rows={3}
        resizable={false}
      />
      <Flex justify="end" gap="sm">
        <Button size="sm" variant="ghost" onClick={() => setBio("")}>Clear</Button>
        <Button size="sm" variant="primary">Save</Button>
      </Flex>
    </Flex>
  );
}
 

Validation Error

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

"use client";
 
import { useState } from 'react';
import { TextArea, Flex } from 'ui-lab-components';
 
export const metadata = {
  title: 'Validation Error',
  description: 'Error styling triggered when the input is non-empty but below a minimum length.'
};
 
export default function Example() {
  const [value, setValue] = useState("");
  const hasError = value.trim().length > 0 && value.trim().length < 20;
 
  return (
    <Flex direction="column" gap="sm" style={{ width: 380 }}>
      <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>
  );
}
 

Disabled & Read-only

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

import { TextArea, Flex } from 'ui-lab-components';
 
export const metadata = {
  title: 'Disabled & Read-only',
  description: 'Side-by-side disabled and read-only states to compare their visual treatment.'
};
 
export default function Example() {
  return (
    <Flex direction="column" gap="md" style={{ width: 380 }}>
      <TextArea
        value="This field is disabled and cannot be edited."
        disabled
        rows={2}
        resizable={false}
      />
      <TextArea
        value="This is a read-only note visible to all team members."
        readOnly
        rows={2}
        resizable={false}
      />
    </Flex>
  );
}
 

Scrollable with maxHeight

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

"use client";
 
import { useState } from 'react';
import { TextArea, Flex } from 'ui-lab-components';
 
export const metadata = {
  title: 'Scrollable with maxHeight',
  description: 'TextArea bounded by a max height — content scrolls once it overflows.'
};
 
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" style={{ width: 380 }}>
      <TextArea
        value={value}
        onChange={(e) => setValue(e.target.value)}
        maxHeight="120px"
        resizable={false}
      />
    </Flex>
  );
}
 
UI Lab