Elixir UIkit
UIkit components and LiveView hooks for Phoenix applications. No Node.js required.
Full documentation is available at hexdocs.pm/elixir_uikit.
Installation
Add elixir_uikit to your list of dependencies in mix.exs:
def deps do
[
{:elixir_uikit, "~> 0.5"}
]
endThen run the setup task:
mix deps.get
mix uikit.setupThis will:
- Remove Tailwind CSS, DaisyUI, and heroicons
-
Add and configure
dart_sassfor SCSS compilation -
Set up
assets/js/app.jswith UIkit imports and LiveView hooks -
Create
assets/css/app.scsswith UIkit SCSS imports - Add component imports to your web module
UIkit's JS and SCSS files are shipped with this package — everything is resolved
from deps/elixir_uikit, so no npm or Node.js installation is needed.
After setup, run mix deps.get again to fetch dart_sass, then start your server:
mix deps.get
mix phx.serverAgent Usage Rules
elixir_uikit ships rules for coding agents (Claude Code, Copilot, etc.) via the usage_rules package. The rules cover component APIs, CSS utilities, JS hooks, and common LiveView patterns — install them so your agent writes idiomatic UIkit code instead of guessing.
Add usage_rules to your deps and configure it in mix.exs:
def project do
[
# ...
usage_rules: [
file: "AGENTS.md",
usage_rules: [:elixir_uikit]
]
]
endThen sync:
mix usage_rules.sync
This pulls usage-rules.md and everything under usage-rules/ into your AGENTS.md (or CLAUDE.md, GEMINI.md, etc. — whichever you point file: at).
Prefer a dedicated skill over inlining? Build one:
usage_rules: [
file: "CLAUDE.md",
skills: [
location: ".claude/skills",
build: [
"elixir-uikit": [
description: "Use this skill when building UI with elixir_uikit components, UIkit CSS, or LiveView hooks (Sortable, Modal, Switcher).",
usage_rules: [:elixir_uikit]
]
]
]
]
The generated SKILL.md is loaded on-demand by the agent, keeping your main CLAUDE.md small.
Usage
Components are automatically imported by the installer. Use them in your HEEx templates:
<.uk_button variant="primary">Click me</.uk_button>
<.uk_card>
<:header><.uk_card_title>Title</.uk_card_title></:header>
<:body>Card content</:body>
</.uk_card>Available Components
uk_button,uk_badge,uk_label,uk_icon,uk_spinneruk_card,uk_card_title,uk_container,uk_section,uk_griduk_modal,uk_modal_title,uk_sortable,uk_subnav,uk_switcheruk_comment,uk_comment_list,uk_dropdown,uk_alertuk_table,uk_thead,uk_tbody,uk_tfoot,uk_caption
uk_table example
<.uk_table striped divider responsive>
<.uk_thead>
<tr>
<th class="uk-table-shrink">#</th>
<th class="uk-table-expand">Name</th>
<th>Status</th>
</tr>
</.uk_thead>
<.uk_tbody id="rows" phx-hook="Sortable">
<tr :for={row <- @rows} id={"row-#{row.id}"}>
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.status}</td>
</tr>
</.uk_tbody>
</.uk_table>
Table sections (uk_thead, uk_tbody, uk_tfoot, uk_caption) are function components with @rest support for passing id, phx-hook, etc.
Modifiers: striped, divider, hover, small, large, justify, middle, responsive, caption_bottom.
Column-level classes (uk-table-shrink, uk-table-expand, uk-table-link) are applied directly to <th> / <td> elements.
Form Components
uk_form,uk_input,uk_checkbox,uk_radio,uk_rangeuk_fieldset,uk_form_label,uk_form_controls,uk_form_icon
uk_input can render text inputs, selects, and textareas. Pass margin when you
want the component to add UIkit's default uk-margin spacing to its own wrapper:
<.uk_input field={@form[:role]} type="select" margin
options={["Admin": "admin", "User": "user"]}
prompt="Select a role...">
<:label>Role</:label>
</.uk_input>LiveView Hooks
The installer sets up three hooks automatically:
Sortable — drag-and-drop reordering:
<.uk_sortable id="my-list" phx-hook="Sortable">
<div :for={item <- @items} id={item.id}>{item.text}</div>
</.uk_sortable>def handle_event("uikit:reorder", %{"items" => item_ids}, socket) do
{:noreply, socket}
endModal — server-controlled show/hide:
<.uk_modal id="my-modal" show={@show_modal} on_close="close_modal">
<:title>Modal Title</:title>
Modal content here.
</.uk_modal>Switcher — tab switching with server sync:
<.uk_subnav id="tabs" switcher active={@active_tab} on_change="tab_changed">
<:item id="tab-1">Tab 1</:item>
<:item id="tab-2">Tab 2</:item>
</.uk_subnav>SCSS Customization
The installer configures dart_sass with a load path pointing to UIkit's SCSS source.
You can customize UIkit variables by overriding them in assets/css/app.scss before the imports:
// Override UIkit variables
$global-primary-background: #1e87f0;
// UIkit (loaded via dart_sass --load-path)
@import "variables-theme";
@import "mixins-theme";
@import "uikit-theme";
/* Your custom styles below */Configuration
Error Translator
By default, form components interpolate %{key} placeholders in error messages.
To use your own translator (e.g., for Gettext/i18n support), configure:
# config/config.exs
config :elixir_uikit, :error_translator, {MyAppWeb.CoreComponents, :translate_error}
The translator function receives {msg, opts} and should return a string.
This is the same signature as Phoenix's generated translate_error/1.