Tableau Theming

View Source

Introduction

Visitors pick a Corex Design theme (neo, uno, duo, leo) from a Corex <.select>. The choice updates data-theme on <html> without a server round-trip, and persists across reloads via localStorage.

Theme is independent from light/dark mode. Corex Design combines them as [data-theme="neo"][data-mode="dark"]. Mode is covered in Tableau Mode. For Phoenix apps with Plugs.Theme and cookies, see Theming.

Install first

Wire the picker allowlist, Theme.head_script/0, and phx:set-theme listeners in site.js before you drop this UI into a layout:

Which theme CSS the design build emits is separate (config :corex_design). See Design and Configuration. Keep the picker list a subset of the themes you build. Run mix corex.design.options for allowed build values.

Already wired?

PieceExpect
Configconfig :my_app, :themes, ~w(neo uno duo leo) (first entry is the default)
ModuleMyApp.Theme with head_script/0, current/1, theme_toggle/1
Layoutdata-theme={@theme} on <html>; {MyApp.Theme.head_script()} in <head>
site.jsSelect hook; phx:set-theme listener writes localStorage + data-theme
CSS@import "../corex/corex.css" and select in components: when you use Design

Full Elixir / site.js paste lives in Tableau: optional theme wiring.

Theme picker

id="theme-select" matches the scaffolded component. Place in your header or toolbar:

<MyApp.Theme.theme_toggle theme={@theme} />

Theme.theme_toggle/1 (from install wiring) renders:

<.select
  id="theme-select"
  class="select ui-size-sm w-auto"
  items={select_items()}
  value={[@theme]}
  positioning={%Corex.Positioning{same_width: false}}
  on_value_change_client="phx:set-theme"
>
  <:label class="sr-only">Theme</:label>
  <:item :let={item}>{item.label}</:item>
  <:trigger>
    <.heroicon name="hero-swatch" />
  </:trigger>
  <:item_indicator>
    <.heroicon name="hero-check" />
  </:item_indicator>
</.select>

on_value_change_client="phx:set-theme" fires a browser event the site.js listener handles. Keep item values in sync with config :my_app, :themes and with the themes array in that listener.

Layout placement

Ensure RootLayout assigns :theme (install wiring) and passes it into shells that render the picker:

<MyApp.Theme.theme_toggle theme={@theme} />

With Tableau Mode, also pass :mode. With Tableau Localize, set lang and dir from your locale module instead of fixed en / ltr. In <head>, call Mode.head_script() then Theme.head_script() when both exist.

CSS

@import "../corex/corex.css";

corex.css loads utilities, configured themes, and components.css. Include select in components: when you use a theme picker. For layered imports, see Design.

Troubleshooting

SymptomCheck
Picker does nothingsite.js listens for phx:set-theme; Select hook is registered
Wrong theme selectedvalue={[@theme]} matches an item value; layout receives :theme
Theme flashes then resetsListener themes / defaultTheme match config and picker items
Styles missing for a themeThat theme is in config :corex_design and you rebuilt with mix corex.design.build
  • Tableau: head_script, config, and site.js listeners
  • Configuration: build vs picker vs generators
  • Design: config :corex_design theme CSS
  • Tableau Mode: data-mode; call Mode.head_script() then Theme.head_script() in <head> when both are used
  • Theming: Phoenix plug and cookie flow