Packages

shadcn/ui-inspired component library for Phoenix LiveView with eject-based distribution. CSS-first theme system, 829 components across 20+ categories — Calendar, Chart, Animation, DnD, Editor, Collaboration, Typography, Navigation, Background, Surface, and more.

Current section

Files

Jump to
phia_ui lib phia_ui components theme_provider.ex
Raw

lib/phia_ui/components/theme_provider.ex

defmodule PhiaUi.Components.ThemeProvider do
@moduledoc """
Runtime theme provider component.
Sets the `data-phia-theme` attribute on a wrapper div, activating the
corresponding CSS custom property overrides from the static `phia-themes.css`
file generated by `mix phia.theme install`.
CSS custom properties cascade naturally: any `bg-primary` inside the wrapper
will use the theme's primary color automatically.
## Usage
<.theme_provider theme={:blue}>
<section class="p-4">
<.button>Blue button</.button>
</section>
</.theme_provider>
<%!-- Custom theme from struct --%>
<.theme_provider theme={@org_theme}>
<%= render_slot(@inner_block) %>
</.theme_provider>
## Setup
Import `phia-themes.css` in your `app.css`:
@import "./phia-themes.css";
Or generate it with:
mix phia.theme install
## Theme values
- Atom (`:zinc`, `:blue`, `:slate`, etc.) — resolves to the theme name string
- `%PhiaUi.Theme{}` struct — uses `theme.name` directly
- `nil` — renders the slot without any `data-phia-theme` attribute (no-op)
"""
use Phoenix.Component
import PhiaUi.ClassMerger, only: [cn: 1]
alias PhiaUi.Theme
attr(:theme, :any,
default: nil,
doc: "Theme key (atom), %PhiaUi.Theme{} struct, or nil for no override"
)
attr(:class, :string, default: nil, doc: "Additional CSS classes for the wrapper div")
attr(:rest, :global, doc: "HTML attributes forwarded to the wrapper div")
slot(:inner_block, required: true, doc: "Content rendered inside the themed wrapper")
@doc """
Wraps content in a scoped theme context.
When `theme` is given, sets `data-phia-theme` on the wrapper div so that
CSS custom properties from `phia-themes.css` cascade into all children.
"""
def theme_provider(assigns) do
assigns = assign(assigns, :theme_name, resolve_name(assigns.theme))
~H"""
<div data-phia-theme={@theme_name} class={cn([@class])} {@rest}>
<%= render_slot(@inner_block) %>
</div>
"""
end
# ---------------------------------------------------------------------------
# Private helpers
# ---------------------------------------------------------------------------
defp resolve_name(nil), do: nil
defp resolve_name(%Theme{name: name}), do: name
defp resolve_name(key) when is_atom(key) do
case Theme.get(key) do
{:ok, theme} -> theme.name
{:error, :not_found} -> nil
end
end
end