# TextArea

> Multiline text field with word-wrap, vertical scrolling, per-line icons and a scrollable read-only mode.

Source: https://crossfly.dev/docs/ui/widgets/textarea — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# TextArea

`TextArea` is the **multiline** text input. On top of the [`TextInput`](/docs/ui/widgets/textinput) base, it adds: word-wrap, line structure, vertical scrolling, 2D coordinate mapping and multiline layout. It supports icons on the right (one per visible line) and a **scrollable read-only mode** (to display long text that the user only scrolls through).

Unlike [`TextField`](/docs/ui/widgets/textfield), `TextArea` **has no mask or password mode**; `ENTER` inserts a line break and `getText()` preserves the `\n`.

> 🟡 · **Package:** `dev.crossfly.ui` · **Extends:** `TextInput` · **Style:** `TextAreaStyle`

## When to use
- Notes, comments, descriptions, addresses — any **multi-line** text.
- Displaying a long scrollable block (with `editable=false`).

## When NOT to use
- **Single-line** input (name, email, value) → use [`TextField`](/docs/ui/widgets/textfield).
- Mask / password mode → use [`TextField`](/docs/ui/widgets/textfield) (`TextArea` does not support them).

## Appearance
Rectangle with background/border from the `TextAreaStyle`, text wrapped into lines (word-wrap at the inner width), with vertical scrolling when the content exceeds the height. The preferred height comes from `rowCount` (number of visible lines) × line height + `ingap`. Right-side icons, when defined, occupy their own column, one per visible line.

``

## Complete example (copy, paste and run)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // Multiline field; LAY_FILL gives height to the scrollable area
      TextArea obs = new TextArea().caption("Observações");
      add(LAY_FILL, obs);

      // Output label
      Label saida = new Label("Escreva algo e toque em Enviar");
      add(LAY_AUTO, saida);

      // There is no onChange per key: read getText() on submit (preserves the \n)
      Button enviar = new Button("Enviar")
         .onAction(c -> saida.setText("Você escreveu " + obs.getText().length() + " caracteres"));
      add(LAY_AUTO, enviar);
   }
}
```

> The snippets below show **only the core** (what goes inside `onShow()`). To run them, place them in the `MainWindow` skeleton above.

## Basic usage
```java
TextArea obs = new TextArea().caption("Observações");
container.add(0.4f, obs);
// ...
String texto = obs.getText();   // preserves the \n
```

## Constructors
| Constructor | Description |
|---|---|
| `TextArea()` | empty |
| `TextArea(String text)` | with initial text (`\r\n`/`\r` normalized to `\n`) |

## Properties and customization
| Property / method | Type | Default | What it does |
|---|---|---|---|
| `text(String)` / `setText(String)` | `TextArea` / `void` | — | sets the text (normalizes line breaks; cursor at start) |
| `getText()` | `String` | — | raw text, preserving `\n` |
| `caption(String)` | `TextArea` (fluent) | `null` | placeholder |
| `rightIcons(Icon...)` | `TextArea` (fluent) | — | right-side icons, one per visible line |
| `rightIconAction(int row, Action)` | `TextArea` (fluent) | — | action of the icon on line `row` (0-based) |
| `clearText()` | `void` | — | clears all text |
| `getNumberOfTextLines()` | `int` | — | total logical lines (word-wrapped) |
| `scrollToTop()` / `scrollToBottom()` / `scrollToLine(int)` | `void` | — | programmatic scrolling |
| style `.rowCount(int)` | `int` | — | no. of visible lines (sets the preferred height) |
| style `.maxLength(int)` | `int` | `0` (unlimited) | character limit |
| style `.validChars(String)` | `String` | `null` | allowed characters (`\n` always accepted) |
| style `.editable(false)` | `boolean` | `true` | scrollable read-only |
| style `.spaceBetweenLines(int)` | `int` | — | extra space between lines |

## Callbacks and events
| Callback | When it fires |
|---|---|
| `onAction(Action)` (inherited) | on `onTouchUp`, after opening the keyboard |
| `onFocus()` / `onBlur()` (inherited) | focus gained / lost |
| `rightIconAction(row, Action)` | on tapping (and releasing over) that line's icon |

## States
- **focused:** blinking cursor, keyboard opens on tap; ↑/↓ arrows navigate between lines.
- **selection:** 2D selection by dragging; long-touch selects all and opens the `ActionSheet`.
- **read-only (`editable=false`):** no cursor/editing; dragging **scrolls** the content; the mouse wheel also scrolls.

### Notes field with a limit
```java
TextArea obs = new TextArea().caption("Observações");
obs.style(Styles.theme()
   .textArea(State.NORMAL)
   .rowCount(4)
   .maxLength(500));
container.add(LAY_AUTO, obs);
```

### Read-only, scrollable text block
```java
TextArea termos = new TextArea(textoDosTermos);
termos.style(Styles.theme()
   .textArea(State.NORMAL)
   .editable(false)      // scroll only, no editing
   .rowCount(8));
container.add(LAY_FILL, termos);
termos.scrollToTop();
```

### Lines with an action icon on the right
```java
TextArea lista = new TextArea("Item A\nItem B\nItem C");
lista.rightIcons(
   new MaterialIcon(""),   // "delete" on line 0
   new MaterialIcon(""),
   new MaterialIcon(""));
lista.rightIconAction(0, c -> removerLinha(0));
container.add(0.3f, lista);
```

## Best practices
- Set `rowCount` in the style to control the visible height; combine it with `LAY_AUTO` in the layout.
- To display long text without editing, use `editable(false)` — dragging then scrolls instead of selecting.
- Use `getText()` to persist (preserves `\n`); `\r\n` normalization is already done on input.

## Common mistakes
- **Expecting a mask or password mode:** `TextArea` does not support them — use [`TextField`](/docs/ui/widgets/textfield).
- **Defining too many `rightIcons`:** only those up to `visibleRows` (no. of visible lines) are drawn; icons beyond that are ignored.

## See also
- Area guide: [`ui/`](/docs/ui) · Recipes: [`cookbook/`](/docs/cookbook)
- Concept (focus, selection, scroll): [`concepts/`](/docs/concepts)
- Related components: [`TextInput`](/docs/ui/widgets/textinput) · [`TextField`](/docs/ui/widgets/textfield) · [`Keypad`](/docs/ui/widgets/keypad)
