# Elixir UIkit

UIkit components and LiveView hooks for Phoenix applications. No Node.js required.

Full documentation is available at [hexdocs.pm/elixir_uikit](https://hexdocs.pm/elixir_uikit).

## Installation

Add `elixir_uikit` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:elixir_uikit, "~> 0.5"}
  ]
end
```

Then run the setup task:

```bash
mix deps.get
mix uikit.setup
```

This will:

- Remove Tailwind CSS, DaisyUI, and heroicons
- Add and configure `dart_sass` for SCSS compilation
- Set up `assets/js/app.js` with UIkit imports and LiveView hooks
- Create `assets/css/app.scss` with 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:

```bash
mix deps.get
mix phx.server
```

## Agent Usage Rules

`elixir_uikit` ships rules for coding agents (Claude Code, Copilot, etc.) via the [`usage_rules`](https://hex.pm/packages/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`:

```elixir
def project do
  [
    # ...
    usage_rules: [
      file: "AGENTS.md",
      usage_rules: [:elixir_uikit]
    ]
  ]
end
```

Then sync:

```bash
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:

```elixir
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:

```heex
<.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_spinner`
- `uk_card`, `uk_card_title`, `uk_container`, `uk_section`, `uk_grid`
- `uk_modal`, `uk_modal_title`, `uk_sortable`, `uk_subnav`, `uk_switcher`
- `uk_comment`, `uk_comment_list`, `uk_dropdown`, `uk_alert`
- `uk_table`, `uk_thead`, `uk_tbody`, `uk_tfoot`, `uk_caption`

#### `uk_table` example

```heex
<.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_range`
- `uk_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:

```heex
<.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:

```heex
<.uk_sortable id="my-list" phx-hook="Sortable">
  <div :for={item <- @items} id={item.id}>{item.text}</div>
</.uk_sortable>
```

```elixir
def handle_event("uikit:reorder", %{"items" => item_ids}, socket) do
  {:noreply, socket}
end
```

**Modal** — server-controlled show/hide:

```heex
<.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:

```heex
<.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:

```scss
// 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:

```elixir
# 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`.
