# How to use checkbox and radio (Option and Group)

> A lone Option becomes a checkbox; several in a Group become a radio (exclusive selection).

Source: https://crossfly.dev/docs/cookbook/ui/checkbox-e-radio — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# How to use checkbox and radio (Option and Group)

**Purpose.** Offer selectable options. A standalone `Option` works as a **checkbox**
(independent on/off). Several `Option`s in the same `Group` work as **radio
buttons** (only one selected at a time). Use a checkbox for independent choices; a radio
for a single choice among alternatives.

## APIs used
- `new Option()` / `new Option(String text)` — creates the option (with or without a label). Starts unchecked.
- `option.checked(boolean checked)` — sets the initial state **without animation** (fluent).
- `option.setChecked(boolean checked)` — changes the state **with a crossfade** animation.
- `option.isChecked()` — returns the current state (`boolean`).
- `option.toggle()` — inverts the state (called internally on touch).
- `option.onAction(Component.Action action)` — callback triggered **when the state changes** by user touch.
- `new Group()` — mutually exclusive selection group.
- `option.group(Group g)` — associates the option with the group (turns it into a radio).
- `group.fade(boolean)` — enables an animated color transition when the selection changes.

> Non-obvious behavior (confirmed in source):
> - In a `Group`, tapping the **already checked** option does not uncheck it (`toggle()` returns early
>   if `checked && getGroup() != null`) — just like a radio: it only changes when you pick another.
> - `onAction` only fires if the state actually changed (`if (checked != prev) runActions()`).
> - Checking via `checked(true)` on a group option already notifies the group and unchecks the others.

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

      // ── Checkbox (standalone Option) ──
      Option aceito = new Option("Aceito os termos");
      aceito.checked(false);                 // initial state, no animation
      aceito.onAction(o -> atualizarBotao(aceito.isChecked()));
      add(aceito);

      // ── Radio (several Options in the same Group) ──
      Group entrega = new Group();

      Option padrao   = new Option("Entrega padrão").group(entrega);
      Option expresso = new Option("Entrega expressa").group(entrega);

      padrao.checked(true);                  // initial selection of the group

      expresso.onAction(o -> escolherFrete("EXPRESSO"));
      padrao.onAction(o -> escolherFrete("PADRAO"));

      add(padrao);
      add(expresso);
   }

   private void atualizarBotao(boolean aceito)
   {
      // ... enable/disable the button according to the checkbox ...
   }

   private void escolherFrete(String tipo)
   {
      // ... react to the shipping choice ...
   }
}
```

> The snippet below shows **just the core**. To run it, place it in the `MainWindow` skeleton above.

## Minimal snippet
```java
// ── Checkbox (standalone Option) ──
Option aceito = new Option("Aceito os termos");
aceito.checked(false);                 // initial state, no animation
aceito.onAction(o -> atualizarBotao(aceito.isChecked()));
add(aceito);

// ── Radio (several Options in the same Group) ──
Group entrega = new Group();

Option padrao  = new Option("Entrega padrão").group(entrega);
Option expresso = new Option("Entrega expressa").group(entrega);

padrao.checked(true);                  // initial selection of the group

expresso.onAction(o -> escolherFrete("EXPRESSO"));
padrao.onAction(o -> escolherFrete("PADRAO"));

add(padrao);
add(expresso);
```

> **Verification note (2026 code).** Confirmed: `Option` implements `Component.Checkable`
> and `AlphaAnimation.Animate`; `Group.select(sender)` unchecks the other members
> (`Option`/`Switch`) automatically. `Group.fade` (default `false`) controls whether the
> change is animated. There is no "value" in the `Group`: to know the selection, check
> `isChecked()` on each `Option`, or store the chosen reference in the callback.

## Dig deeper
- Widget pages: [Option](/docs/ui/widgets/option) · [Group](/docs/ui/widgets/group)
- Dropdown (single selection in a popup): [dropdown-selecao.md](/docs/cookbook/ui/dropdown-selecao)
