# Textarea

A textarea allows people to enter long, free-form text data, like a comment. If you only need someone to enter one line of information, try an input instead.

## Best practices

### Do

- Size the textarea to the approximate volume of expected content.
- Pair placeholder text with a visible label.

### Don't

- Use placeholder text for essential information.
- Put too much information in the placeholder.
- Rely on placeholder text instead of a persistent label or helper text.

## Behavior and states

- Textareas aren’t resizable by default.
- Overflow content scrolls within the textarea.
- The resize property can let people control how much information they see.
- Size the textarea for the approximate volume of expected content.

## Default

Source: CoreAI.

[Download source](/coreai-design-system/source/examples/components-textarea--default.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { TextareaProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";
import * as React from 'react';

export const Default = (props: Partial<TextareaProps>): JSXElement => (<Field label="Default Textarea">
    <Textarea {...props}/>
  </Field>);

export default Default;
```

## API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. `?` means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

### Textarea API

```ts
interface TextareaProps {
  /**
   * Styling the Textarea should use.
   * @default 'filled-darker'
   */
  appearance?: "outline" | "filled-darker" | "filled-lighter" | "filled-darker-shadow" | "filled-lighter-shadow";

  as?: "textarea";

  children?: any;

  className?: string;

  /**
   * The default value of the Textarea.
   */
  defaultValue?: string;

  /**
   * Callback for when the user changes the value.
   */
  onChange?: ((ev: ChangeEvent<HTMLTextAreaElement>, data: TextareaOnChangeData) => void);

  ref?: Ref<HTMLTextAreaElement>;

  /**
   * Which direction the Textarea is allowed to be resized.
   * @default none
   */
  resize?: "none" | "both" | "horizontal" | "vertical";

  /**
   * Wrapper element used for displaying the borders for Textarea. This wrapper is needed due to the focus
   * indicator border animation. For more information, see Spec.md
   *
   * The root only receives `className` and `style`. All other props are applied to the `textarea` slot.
   */
  root?: NonNullable<WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null; }, "children"> & { children?: any; }> | null> | undefined;

  /**
   * Size of the Textarea.
   * @default medium
   */
  size?: "small" | "medium" | "large";

  style?: CSSProperties;

  /**
   * The `<textarea>` element. This is the primary slot, all native props and ref are applied to this slot.
   */
  textarea?: NonNullable<WithSlotShorthandValue<{ as?: "textarea"; } & Omit<Omit<DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref"> & { ref?: ((instance: HTMLTextAreaElement | null) => void) | RefObject<HTMLTextAreaElement> | null; }, "children"> & { children?: any; }> | null> | undefined;

  /**
   * The value of the Textarea.
   */
  value?: string;
}
```

## Implementation

CoreAI 0.12.0; Fluent 9.74.9.

[Setup and dependencies](/coreai-design-system/guides/Package.md).

Import components from `@coreai-ds/react-components`. CoreAI guidance above takes precedence over API demonstration examples.

## Appearance

Source: Fluent, adapted for CoreAI.

Textarea can have different appearances.
The colors adjacent to the Textarea should have a sufficient contrast. Particularly, the color of input with
      filled darker and lighter styles needs to provide a contrast ratio greater than 3 to 1 against the immediate
      surrounding color to pass accessibility requirement.

[Download source](/coreai-design-system/source/examples/components-textarea--appearance.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    base: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalMNudge,
    },
    inverted: {
        backgroundColor: tokens.colorNeutralBackgroundInverted,
    },
    invertedLabel: {
        color: tokens.colorNeutralForegroundInverted2,
    },
    fieldWrapper: {
        padding: `${tokens.spacingVerticalMNudge} ${tokens.spacingHorizontalMNudge}`,
    },
});

export const Appearance = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.base}>
      <div className={styles.fieldWrapper}>
        <Field label="Textarea with Outline appearance">
          <Textarea appearance="outline" placeholder="type here..." resize="both"/>
        </Field>
      </div>

      <div className={mergeClasses(styles.fieldWrapper, styles.inverted)}>
        <Field label={{ children: 'Textarea with Filled Darker appearance', className: styles.invertedLabel }}>
          <Textarea appearance="filled-darker" placeholder="type here..." resize="both"/>
        </Field>
      </div>

      <div className={mergeClasses(styles.fieldWrapper, styles.inverted)}>
        <Field label={{ children: 'Textarea with Filled Lighter appearance', className: styles.invertedLabel }}>
          <Textarea appearance="filled-lighter" placeholder="type here..." resize="both"/>
        </Field>
      </div>
    </div>);
};

export default Appearance;
```

## Controlled

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-textarea--controlled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { TextareaProps } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";

export const Controlled = (): JSXElement => {
    const [value, setValue] = React.useState('initial value');
    const onChange: TextareaProps['onChange'] = (ev, data) => {
        if (data.value.length <= 50) {
            setValue(data.value);
        }
    };
    return (<Field label="Controlled Textarea limiting the value to 50 characters">
      <Textarea value={value} onChange={onChange}/>
    </Field>);
};

export default Controlled;
```

## Disabled

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-textarea--disabled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";
import * as React from 'react';

export const Disabled = (): JSXElement => (<Field label="Disabled Textarea">
    <Textarea disabled/>
  </Field>);

export default Disabled;
```

## Placeholder

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-textarea--placeholder.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";
import * as React from 'react';

export const Placeholder = (): JSXElement => (<Field label="Textarea with placeholder">
    <Textarea placeholder="type here..."/>
  </Field>);

export default Placeholder;
```

## Resize

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-textarea--resize.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    base: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalMNudge,
    },
});

export const Resize = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.base}>
      <Field label='Textarea with resize set to "none"'>
        <Textarea resize="none"/>
      </Field>

      <Field label='Textarea with resize set to "vertical"'>
        <Textarea resize="vertical"/>
      </Field>

      <Field label='Textarea with resize set to "horizontal"'>
        <Textarea resize="horizontal"/>
      </Field>

      <Field label='Textarea with resize set to "both"'>
        <Textarea resize="both"/>
      </Field>
    </div>);
};

export default Resize;
```

## Size

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-textarea--size.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    base: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalMNudge,
    },
});

export const Size = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.base}>
      <Field size="small" label="Small Textarea">
        <Textarea />
      </Field>

      <Field size="medium" label="Medium Textarea">
        <Textarea />
      </Field>

      <Field size="large" label="Large Textarea">
        <Textarea />
      </Field>
    </div>);
};

export default Size;
```

## Uncontrolled

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-textarea--uncontrolled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Textarea } from "@coreai-ds/react-components";
import type { TextareaProps } from "@coreai-ds/react-components";
import * as React from 'react';

const onChange: TextareaProps['onChange'] = (ev, data) => {
    // Uncontrolled inputs can be notified of changes to the value
    console.log(`New value: "${data.value}"`);
};

export const Uncontrolled = (): JSXElement => (<Field label="Uncontrolled Textarea" hint="Check console for new value">
    <Textarea onChange={onChange} placeholder="type here..."/>
  </Field>);

export default Uncontrolled;
```

## Resources

- [Figma component](https://www.figma.com/design/eXfSQrRg3poHRgmr0ivN5V/CoreAI-Figma-Library?node-id=62039-177849)
- [Fluent guidance](https://fluent2.microsoft.design/components/web/react/core/textarea/usage)