# compiling with a different theme

> `--theme <file>` compiles an app with the theme in that file INSTEAD of its own. It is a replacement, never a merge, so the look you get is one you can point at a file for. Use it to present several apps consistently, or to ship one app under more than one brand.

<!-- id: ui-theme-override · area: ui · stability: stable · html: https://osysharp.com/reference/ui/theme-override/ -->

## Signature   {#signature}
```text
osy compile  --theme <file>
osy validate --theme <file>
```

## Summary        {#summary}
An app's look lives in its `theme` block ([theme tokens](https://osysharp.com/reference/ui/theming/)). **`--theme <file>` compiles the app with a different
one**, without editing a line of it:

```console
$ osy validate --theme ../brand/acme.osy     # offline, no database — check it resolves first
$ osy compile  --theme ../brand/acme.osy     # then compile the app wearing it
```

Two things this is for:

- **One brand, many apps.** A theme cannot be imported across apps — a manifest globs its own directory — so
  sharing a house style otherwise means copying a file into every project. One file passed at compile time
  dresses all of them.
- **Presenting several apps together.** Documentation and demos show an app to explain a *feature*. When the
  apps each have their own palette, a reader compares styling instead of reading the point. Compile them under
  one theme for the occasion; the apps keep their own.

## What it does   {#description}

`--theme` takes the `theme` block out of the app's own sources and puts the one in your file there instead. The
rest of the app — its entities, its pages, its components — compiles exactly as it always does; only the tokens
change. Nothing in the app has to be written differently to be themeable this way.

## It replaces, it does not merge   {#replaces}

Every `theme` declaration in the app's own sources is removed, and the file you pass supplies the theme. Tokens
the app declared and the override omits are **gone**, not inherited.

This is deliberate. A merge would produce a theme that exists in neither file — so the thing on screen could not
be reproduced by compiling anything, which is exactly what you need from a screenshot or a shipped build.

## A token the override lacks is an error, by name   {#missing-tokens}

Because it replaces, an app that names a token your file does not declare will not compile:

```text
model/chrome.osy:12:53  ERROR  RESOLVE_ERROR  UI: the `Colors` group declares no token 'Bulb'
  — its tokens are Bg, Border, Danger, Muted, OnBg, OnPrimary, Primary, Success, Surface, …
```

That is the useful answer, not an obstacle: it tells you either to add the token to your theme, or that this
app's look is not substitutable. An app built on a handful of semantic colours takes almost any theme; one whose
palette *is* its subject — a game, a visual demo — will list everything it needs, which is a fair description of
why it should keep its own.

**So a theme meant to dress several apps is a superset**: it declares every token those apps name. Start from the
kit's own token names ([theme tokens](https://osysharp.com/reference/ui/theming/)) — an app that shadows kit tokens rather than inventing parallel ones is an
app almost any override fits.

## The swap is announced   {#announced}

Every run says what it did:

```text
⚠ theme override: acme.osy replaces `Doc` in model/theme.osy.
```

The app is not wearing its own look, so the output says so — a build or a screenshot taken from it should never
be mistaken for the app as it ships.

## What goes in the file you pass   {#the-file}

One `theme` block, and normally nothing else:

```osy title="a theme file to pass to --theme" test app=ui-theme-override
theme Docs {
  Colors {
    Primary   = "#125E7A";
    OnPrimary = "#FFFFFF";
    Bg        = "#FAF9F7";
    OnBg      = "#14181D";
    Surface   = "#FFFFFF";
    Border    = "#E4E2DC";
  }
  Radius { Md = "10px"; }
}
```

A file declaring **no** theme is refused, and so is one declaring **two** — with two, which one dressed the app
would depend on declaration order, which is not something you should have to know to read a screenshot.

Anything else in the file compiles as usual, and a `theme` block in the app that shares a file with components
loses only the block: the rest of the file is untouched.

## See also   {#see-also}
- [theme tokens](https://osysharp.com/reference/ui/theming/) — declaring tokens, the groups they live in, and light/dark modes.
- [color palettes](https://osysharp.com/reference/ui/palette/) — turning one seed colour into a full ramp.
- [Osysharp.Ui (the UI kit)](https://osysharp.com/reference/ui/kit/) — the starter theme every app inherits, and the token names to shadow.
