# Button

> Clickable button that displays text and/or icon, with a pressed state and onAction.

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

# Button

`Button` is the most basic interactive component: it displays text and/or an icon and fires an action when tapped, with a visual pressed state (via `ButtonStyle`). When there is text **and** an icon, their relative position is controlled by the enum [`TextPos`](/docs/reference). It is also the base of other widgets (for example, `Dropdown extends Button`).

The action is registered with `onAction(Action)` (inherited from `Component`); the trigger occurs in the standard click flow (`runActions()` in `onTouchUp`), not in `onTouchDown`.

> 🟢 · **Package:** `dev.crossfly.ui` · **Extends:** `Component` · **Style:** `ButtonStyle`

## When to use
- Any tappable action: save, confirm, navigate, open a dialog.
- Icon-only button (toolbar) or text-only button (link/secondary action).

## When NOT to use
- Static label → use [`Label`](/docs/ui/widgets/label).
- Persistent on/off toggle → use `Switch`/`Option` (see [`ui/`](/docs/ui)).

## Appearance
Text and/or icon centered inside the button. With both present, the `[icon + gap + text]` block is centered on both axes; `icongap` defines the spacing. Positioning follows `TextPos`:

| `TextPos` | Layout | `isHorizontal()` |
|---|---|---|
| `NONE` | text and icon overlapped (centered) | false |
| `TEXT_AT_LEFT` | text to the left of the icon | true |
| `TEXT_AT_RIGHT` | text to the right of the icon | true |
| `TEXT_AT_TOP` | text above the icon | false |
| `TEXT_AT_BOTTOM` | text below the icon | false |

If `textPos == null`, the default is centered overlap (equivalent to `NONE`).

``

## 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());

      // Label that shows how many times the button was tapped
      Label saida = new Label("Cliques: 0");
      add(LAY_AUTO, saida);

      // Mutable counter used inside the callback (1-element array)
      final int[] cliques = {0};

      // Button that increments the counter and updates the Label on each tap
      Button botao = new Button("Clique aqui")
         .onAction(c -> saida.setText("Cliques: " + (++cliques[0])));
      add(LAY_AUTO, botao);
   }
}
```

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

## Basic usage
```java
Button b = new Button("Salvar").onAction(c -> salvar());
container.add(LAY_AUTO, b);
```

## Constructors
| Constructor | Description |
|---|---|
| `Button(String text)` | text-only button |
| `Button(Icon icon)` | icon-only button |
| `Button(String text, Icon icon, TextPos textPos)` | text + icon with relative position |

## Properties and customization
| Property / method | Type | Default | What it does |
|---|---|---|---|
| `setText(String)` | `void` | — | swaps the text, invalidates layout and calls `repaint()` |
| `icon(Icon, TextPos)` | `Button` (fluent) | — | sets the icon and its position relative to the text |
| `text` / `icon` / `textPos` | public fields | — | current content (can be read/assigned) |
| style `.pressable()` | — | — | enables the pressed highlight |
| style `.textAlign(Position, Position)` | `Position` | theme | content alignment |
| style `.autoWidth(Relative)` / `.autoHeight(Relative)` | `Relative` | — | fixes the preferred size |
| `getAutoWidth()` / `getAutoHeight(int)` | `int` | — | content-based preferred sizes |

## Callbacks and events
| Callback | When it fires |
|---|---|
| `onAction(Action)` | on completing the click (touch-up), via `runActions()`. Returns `this`, allowing chaining (`new Button(...).onAction(...).style(...)`). |

The `Action` is `c -> { ... }`, where `c` is the originating `Component`; it may throw `Exception`.

## States
- **pressed:** while pressed, the `ButtonStyle` applies the pressed style (with fade). Requires `pressable()` in the style.
- **disabled:** `setEnabled(false)` applies the disabled appearance and ignores touches.

### Button with icon to the right of the text
```java
Button proximo = new Button(
   "Próximo", new MaterialIcon(""), TextPos.TEXT_AT_RIGHT);
container.add(LAY_AUTO, proximo);
```

### "Link"-style button that clears fields
```java
Button clear = new Button("Clear").style(
   Styles.theme().button(ButtonRole.LINK, State.NORMAL)
      .pressable()
      .textAlign(Position.CENTER, Position.CENTER));
clear.onAction(c -> {
   nome.clearText();
   email.clearText();
});
container.add(LAY_AUTO, clear);
```

## Best practices
- Always pass `textPos` when the button has text **and** an icon (otherwise they overlap).
- Use theme roles (`ButtonRole.PRIMARY`/`SECONDARY`/`LINK`) for visual consistency.
- To space buttons, use `Gap` or `ingap`/`outgap`/layout fractions — `Spacer` was removed (see [`spacing.md`](/docs/ui/widgets/spacing)).

## Common mistakes
- **`text` + `icon` without `textPos`:** the result overlaps (`null` behavior = `NONE`).
- **Expecting the trigger on `onTouchDown`:** the action fires in the standard click flow (touch-up).

## See also
- Area guide: [`ui/`](/docs/ui) · Recipes: [`cookbook/`](/docs/cookbook)
- Concept (component model / `onAction`): [`concepts/`](/docs/concepts)
- Related components: [`Label`](/docs/ui/widgets/label) · [`ImageView`](/docs/ui/widgets/imageview)
