Generates CSS custom property declarations from a %PhiaUi.Theme{} struct.
This module is responsible for converting PhiaUI theme data into valid CSS strings. It supports three output modes that cover the most common scenarios:
1. Root-scoped CSS (single active theme)
Use generate/2 when you want one theme to apply globally to your
application. The output uses :root and .dark selectors.
theme = PhiaUi.Theme.get!(:blue)
css = PhiaUi.ThemeCSS.generate(theme)
# => "/* PhiaUI Theme: Blue */\n@theme { ... }\n:root { ... }\n.dark { ... }"Inject the output as a <style> tag or write it to assets/css/theme.css
via mix phia.theme apply blue.
2. Attribute-scoped CSS (multi-theme, one theme per block)
Use generate_for_selector/1 to scope a theme to a [data-phia-theme]
attribute selector instead of :root. This is the format used by
mix phia.theme install.
css = PhiaUi.ThemeCSS.generate_for_selector(theme)
# => ~s([data-phia-theme="blue"] { ... }\n.dark [data-phia-theme="blue"] { ... })The resulting CSS is activated by setting the data-phia-theme attribute on
any ancestor element:
<html data-phia-theme="blue" class="dark">3. All themes in one file
Use generate_all/1 to combine every preset into a single CSS file, each
scoped to its own [data-phia-theme] selector. This is the output of
mix phia.theme install.
css = PhiaUi.ThemeCSS.generate_all()
# => one block per theme, sorted alphabetically
# Or for a subset of presets:
css = PhiaUi.ThemeCSS.generate_all([:zinc, :blue])JSON round-trip
Themes can be serialised to JSON and back for storage, sharing, or editing:
json = PhiaUi.ThemeCSS.to_json(theme)
theme = PhiaUi.ThemeCSS.from_json(json)CSS custom property naming convention
Color tokens use --color-{name} with underscores replaced by hyphens:
:card_foreground→--color-card-foreground:primary→--color-primary:sidebar_background→--color-sidebar-background
Non-color tokens (radius, typography) are emitted inside an @theme { }
block using the --radius and --font-* naming scheme.
Summary
Functions
Deserialises a JSON string into a %PhiaUi.Theme{} struct.
Generates a CSS string from a %PhiaUi.Theme{} struct.
Generates a complete CSS string containing all (or a selected subset of)
themes, each scoped to its [data-phia-theme] attribute selector.
Generates a CSS string scoped to [data-phia-theme="<name>"] attribute
selectors, without any @theme { } block or :root selector.
Serialises a %PhiaUi.Theme{} to a pretty-printed JSON string.
Functions
@spec from_json(String.t()) :: PhiaUi.Theme.t()
Deserialises a JSON string into a %PhiaUi.Theme{} struct.
Expects the JSON schema produced by to_json/1. Raises Jason.DecodeError
for malformed JSON and KeyError if required fields (name, label,
colors) are missing.
Example
iex> theme = PhiaUi.Theme.get!(:zinc)
iex> json = PhiaUi.ThemeCSS.to_json(theme)
iex> restored = PhiaUi.ThemeCSS.from_json(json)
iex> restored.name
"zinc"
iex> restored.label
"Zinc"
@spec generate( PhiaUi.Theme.t(), keyword() ) :: String.t()
Generates a CSS string from a %PhiaUi.Theme{} struct.
Produces:
- An optional
@theme { }block with radius and typography tokens (controlled by the:include_theme_blockoption). - A light-mode block using the
:selector(default":root"). - A dark-mode block using the
:dark_selector(default".dark").
Options
:selector— CSS selector for light-mode variables (default:":root"):dark_selector— CSS selector for dark-mode variables (default:".dark"):include_theme_block— emit the@theme { }block (default:true)
Examples
iex> theme = PhiaUi.Theme.get!(:zinc)
iex> css = PhiaUi.ThemeCSS.generate(theme)
iex> String.contains?(css, ":root {")
true
iex> String.contains?(css, ".dark {")
true
iex> String.contains?(css, "@theme {")
trueOverride the selector for a custom scope:
iex> theme = PhiaUi.Theme.get!(:blue)
iex> css = PhiaUi.ThemeCSS.generate(theme, selector: "#app", dark_selector: "#app.dark")
iex> String.contains?(css, "#app {")
trueOmit the @theme block when composing multiple themes:
iex> theme = PhiaUi.Theme.get!(:rose)
iex> css = PhiaUi.ThemeCSS.generate(theme, include_theme_block: false)
iex> String.contains?(css, "@theme {")
false
@spec generate_all([atom() | PhiaUi.Theme.t()] | nil) :: String.t()
Generates a complete CSS string containing all (or a selected subset of)
themes, each scoped to its [data-phia-theme] attribute selector.
This is the output written by mix phia.theme install. The resulting file
is designed to be imported into assets/css/app.css and does not contain
any @theme { } blocks — those remain in the base theme.css.
Themes are sorted alphabetically by name for deterministic, diffable output.
Arguments
nil(default) — includes all built-in presets fromTheme.list/0.- A list of atoms, e.g.
[:zinc, :blue, :rose]— loads those named presets. - A list of
%Theme{}structs — uses the structs directly (custom themes).
Examples
iex> css = PhiaUi.ThemeCSS.generate_all()
iex> String.contains?(css, ~s([data-phia-theme="zinc"]))
true
iex> String.contains?(css, ~s([data-phia-theme="blue"]))
trueSubset of themes:
iex> css = PhiaUi.ThemeCSS.generate_all([:zinc, :blue])
iex> String.contains?(css, ~s([data-phia-theme="zinc"]))
true
iex> String.contains?(css, ~s([data-phia-theme="rose"]))
falseThe generated file begins with a usage comment:
/* PhiaUI Themes — generated by mix phia.theme install
* Usage: import this file and set data-phia-theme on any ancestor element
* Example: <html data-phia-theme="blue" class="dark">
*/
@spec generate_for_selector(PhiaUi.Theme.t()) :: String.t()
Generates a CSS string scoped to [data-phia-theme="<name>"] attribute
selectors, without any @theme { } block or :root selector.
This is the multi-theme format: multiple themes can coexist in the same CSS
file, each activated by setting data-phia-theme on an ancestor element.
Dark mode is handled by prefixing the selector with .dark.
The output for the :blue theme looks like:
[data-phia-theme="blue"] {
--color-background: oklch(1 0 0);
--color-primary: oklch(0.546 0.245 262.881);
...
}
.dark [data-phia-theme="blue"] {
--color-background: oklch(0.145 0.01 237.938);
...
}Example
iex> theme = PhiaUi.Theme.get!(:blue)
iex> css = PhiaUi.ThemeCSS.generate_for_selector(theme)
iex> String.contains?(css, ~s([data-phia-theme="blue"]))
true
iex> String.contains?(css, ~s(.dark[data-phia-theme="blue"]))
true
@spec to_json(PhiaUi.Theme.t()) :: String.t()
Serialises a %PhiaUi.Theme{} to a pretty-printed JSON string.
The output can be redirected to a file and later restored with from_json/1
or passed to mix phia.theme import. Requires :jason as a dependency
(available as a transitive dependency of Phoenix).
Example
iex> theme = PhiaUi.Theme.get!(:zinc)
iex> json = PhiaUi.ThemeCSS.to_json(theme)
iex> String.contains?(json, "\"name\"")
true
iex> String.contains?(json, "\"zinc\"")
true