# Styles and themes

> The appearance model — Skin is structure, Theme are semantic roles per mode — and runtime theme switching.

Source: https://crossfly.dev/docs/concepts/styling-and-theming-model — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Styles and themes

Appearance in CrossFly boils down to a mnemonic from the framework itself:

> **Skin = structure / renderer · Theme = semantic roles per mode.**

Three distinct responsibilities collaborate.

## 1. Style per state (default / focused / pressed)
Each `Component` can have **up to three styles** and the framework picks the right one per frame according to the
interaction. This is why a button "sinks" when pressed without you animating anything.
```java
comp.style(normal).focusedStyle(focado).pressedStyle(apertado);
```

## 2. `Skin` — the shape factory
The `Skin` defines the **structure**: corner radii, border thicknesses, spacings, default icons. There are
`MaterialSkin`, `IOSSkin`, `FlutterSkin`. A custom `Skin` overrides **shape/spacing** — never
color. Swapping the global `Skin` re-clothes all components.

## 3. `Theme` + `ColorScheme` — the semantic roles
The **colors** come from roles (PRIMARY, SURFACE, ON_SURFACE, ERROR, TITLE, HINT…) resolved to the current
**light/dark mode**, from a `ColorScheme` generated from a **seed color** (Material You).
```java
Styles.theme(0xFF6750A4, ThemeMode.DARK);   // one call themes everything, in dark mode
```

## The most powerful point: switching theme at runtime without recreating the UI
Here is the subtlety that makes light/dark mode trivial:

- The colors of the styles are not "frozen" values — they are **`PalColor`**, **live** references to the
  palette.
- There is a **global style version counter** (`styleVersion`). When applying a new scheme /
  toggling the mode, the framework **increments the version** and reapplies the theme across all open windows —
  each style based on `PalColor` **re-resolves its colors on the next frame**. No component is
  destroyed and recreated.

Complementing this, components whose style **changes in shape** by mode register how to restyle themselves
(`onRestyle`/`styled`) and `restyle()` reapplies the subtree in place:
```java
Label titulo = new Label("Bem-vindo").styled(() -> Styles.theme().label(LabelRole.TITLE));
// ...when the mode is toggled, the framework re-evaluates this provider and re-skins without recreating the Label.
Styles.toggleDarkMode();
```

## Why this architecture
- **Separating shape (Skin) from color (Theme)** lets you swap visual identity and palette
  independently — and adapt to light/dark without touching the Skin.
- **`PalColor` + version** turns "switching theme" from "rebuild the tree" into "re-resolve colors on the
  next frame" — cheap and without flicker.

## See also
- Apply: [Themes and styles](/docs/ui/theming) · [Light/dark mode](/docs/ui/theming/dark-mode)
- Next: [The lifecycle](/docs/concepts/lifecycle)
