# Switchers - agent guide

> Normative extract of the EchoSistema template for the page
> `/componentes/seletores`. Copy it verbatim: tag names, props, events and classes
> are contract.
>
> Full guide (rules, tokens and every family): `/agents/echosistema-ui.md`

## Rules that apply before any line of code

- Colour only through tokens (`text-fg1`, `bg-panel`, `border-line`, `.es-i--*`); never a hex, never a Tailwind colour.
- Two axes: the intent gives the colour, the variant consumes it. Never combine them by hand.
- Visible text through `t()`; tag names, props and classes stay literal.
- A component does not fetch: it takes props and emits events.
- An icon alone inside a button needs an `aria-label`.

The small menus that CHANGE the site rather than navigate it. All of them over
`<element-switch-dropdown>`: opening one closes the others, an outside click
closes, Escape closes and gives focus back to the trigger.

```vue
<element-theme-switch />                       <!-- flat is the DEFAULT -->
<element-language-switch compact />            <!-- the flag alone -->
<element-currency-switch :trigger-class="LENS" />

<element-switch-dropdown :label="t('sort')" start up menu-class="min-w-52">
  <template #trigger>…</template>
  <template #default="{ choose }">
    <li><button type="button" class="es-menu-item w-full" @click="choose(); select(x)">…</button></li>
  </template>
</element-switch-dropdown>
```

| Prop | What it does |
| --- | --- |
| `up` | opens upwards (trigger at the bottom) |
| `start` | anchors by the left edge (trigger on the left) |
| `trigger-class` | replaces the WHOLE trigger skin (it does not merge with the default) |
| `compact` (language) | the flag alone, with no language name |
| `menu-class` | the menu's width |

Three ready skins: flat (the default), the round lens
(`es-lens h-9 gap-2 rounded-full px-2.5 text-[12.5px]`) and icon-only. In a bar
they come from `useBarSkin(lens)`, which changes the icon buttons and the menus
TOGETHER - mixing the two is worse than either.

The menu is TELEPORTED to the body and positioned `fixed` from the trigger's
rectangle: an absolutely positioned menu is clipped by any ancestor with
`overflow: hidden` and covered by any stacking context, and a masthead creates
one (it carries `backdrop-filter`).

The theme control is a MENU, never a button that cycles: cycling hides the
options and shows only the current state. Its three icons are sun, moon and a
MONITOR for the system theme.

**Where the options come from:** language and currency read the platform's
catalogue (`GET /api/v1/languages`, `GET /api/v1/currencies`) through
`useLanguages()` and `useCurrency()`. Theme, width and palette are browser
preferences and have no endpoint. The language menu shows the INTERSECTION of
the catalogue and what the site offers, because the URL owns the locale.

---

Source: `app/components/element/*.vue`
