# Light/dark mode

> Switch theme in real time without rebuilding the UI — setDarkMode + onRestyle/styled/restyle.

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

# Light/dark mode

CrossFly switches between light and dark **in real time and in place** — without recreating screens. The key is
`Styles.setDarkMode(...)` combined with styles that **re-resolve** from the theme.

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // Styles, ThemeMode, LabelRole

/** 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();
      Styles.setColorScheme(0xFF6750A4, ThemeMode.LIGHT);   // base palette (follows light/dark)
      setLayout(new VerticalLayout());

      // styled(...) re-evaluates the style on each theme switch (automatic re-skin per mode)
      Label titulo = new Label("Bem-vindo")
         .styled(() -> Styles.theme().label(LabelRole.TITLE));
      add(LAY_AUTO, titulo);

      // Switch toggles the mode; setDarkMode re-skins the whole open UI on its own.
      Switch alternar = new Switch("Modo escuro");
      alternar.onAction(c -> Styles.setDarkMode(alternar.isChecked()));
      add(LAY_AUTO, alternar);
   }
}
```
> The snippets below show **only the core** (what goes inside `onShow()`). To run them, place them in the `MainWindow` skeleton above.

## The automatic way (recommended)
1. Use **theme `PalColor`** (`Styles.textColor`, `cs.surface`) in styles — they re-resolve themselves.
2. Call `setDarkMode(...)`:
```java
Styles.toggleDarkMode();              // toggles light ↔ dark
Styles.setDarkMode(true);             // forces dark
boolean escuro = Styles.isDarkMode(); // current state
```
`setDarkMode(...)` already **re-applies the theme to all open windows** automatically (it triggers
`restyleAll()` internally), so styles bound to `PalColor` change color without any extra code.

## Styles that depend on the mode → `styled(...)` / `onRestyle(...)`
When the style **changes shape** according to the mode (not just the color), register how the component should
re-style itself. The callback runs once immediately and again on each theme switch:
```java
Label titulo = new Label("Bem-vindo")
   .styled(() -> Styles.theme().label(LabelRole.TITLE));   // re-evaluated on each theme switch

// for logic beyond style (swap icon glyph, chart color, etc.):
Label l = new Label("Status");
l.onRestyle(() -> l.style(Styles.isDarkMode() ? estiloEscuro : estiloClaro));
```

## Manual re-skin of a subtree
If you changed the theme non-globally (e.g., just one panel), force the reapplication:
```java
window.restyle();   // re-runs all onRestyle in the tree and repaints, without recreating components
```

## Complete flow
```java
Switch alternar = new Switch("Modo escuro");
alternar.onAction(c -> Styles.setDarkMode(alternar.isChecked()));  // the whole UI follows along
```

## Best practices
- Prefer **theme `PalColor`** over fixed colors — dark mode becomes automatic.
- For styles that change structure per mode, use **`styled(...)`** (leaner than `onRestyle`).
- Read the mode with `Styles.isDarkMode()` / `Styles.themeMode()` when **building** styles.

## Common mistakes
- Storing fixed colors (`0xFF...`) and then having to rebuild the screen by hand for dark mode.
- Rebuilding the entire UI when switching theme — use `restyle()`/`styled(...)` and reuse the components.

## See also
- [Color schemes](/docs/ui/theming/color-schemes) · [Styling components](/docs/ui/theming/styling-components) · [Skins](/docs/ui/theming/skins)
