PhiaUi.Components.InlineEditTable (phia_ui v0.1.17)

Copy Markdown View Source

Inline-editable table row components for in-place data editing.

All state (which rows are in edit mode, saving state) lives in the LiveView. These components are purely presentational — they switch between a read view and an edit view based on @editing assigns.

Sub-components

FunctionHTML elementPurpose
editable_cell/1<td>Single cell toggling view ↔ edit mode
editable_row/1<tr>Row wrapper that applies edit-mode styling
editable_row_actions/1<td>Save + Cancel action cell for editing rows

Example

defmodule MyAppWeb.ProductsLive do
  use MyAppWeb, :live_view

  def handle_event("start_edit", %{"id" => id}, socket) do
    {:noreply, assign(socket, editing_id: id)}
  end

  def handle_event("save_row", %{"id" => id}, socket) do
    # persist changes, then:
    {:noreply, assign(socket, editing_id: nil)}
  end

  def handle_event("cancel_edit", _params, socket) do
    {:noreply, assign(socket, editing_id: nil)}
  end

  def render(assigns) do
    ~H"""
    <.table>
      <.table_body>
        <%= for product <- @products do %>
          <% editing = to_string(product.id) == @editing_id %>
          <.editable_row editing={editing}>
            <.editable_cell editing={editing}>
              <:view>{product.name}</:view>
              <:edit>
                <input type="text" name="name" value={product.name}
                       class="h-8 w-full rounded border border-input px-2 text-sm" />
              </:edit>
            </.editable_cell>
            <.editable_cell editing={editing}>
              <:view>{product.price}</:view>
              <:edit>
                <input type="number" name="price" value={product.price}
                       class="h-8 w-24 rounded border border-input px-2 text-sm text-right" />
              </:edit>
            </.editable_cell>
            <%= if editing do %>
              <.editable_row_actions
                row_id={to_string(product.id)}
                on_save="save_row"
                on_cancel="cancel_edit"
              />
            <% else %>
              <.table_cell>
                <.button variant={:ghost} size={:sm}
                         phx-click="start_edit"
                         phx-value-id={to_string(product.id)}>Edit</.button>
              </.table_cell>
            <% end %>
          </.editable_row>
        <% end %>
      </.table_body>
    </.table>
    """
  end
end

Summary

Functions

Renders a <td> that switches between a read view and an edit view.

Renders a <tr> wrapper that applies edit-mode visual styling.

Renders a <td> containing Save and Cancel buttons for an editing row.

Functions

editable_cell(assigns)

Renders a <td> that switches between a read view and an edit view.

Only one slot is rendered at a time — determined by @editing. This keeps the server-rendered HTML minimal while making the transition seamless from the user's perspective.

Example

<.editable_cell editing={@editing_id == product.id}>
  <:view>{product.sku}</:view>
  <:edit>
    <input type="text" name="sku" value={product.sku}
           class="h-8 w-full rounded border border-input px-2 text-sm" />
  </:edit>
</.editable_cell>

Attributes

  • editing (:boolean) - When true, the :edit slot is displayed and :view is hidden. When false, the :view slot is displayed and :edit is hidden.

    Defaults to false.

  • class (:string) - Additional CSS classes for the <td>. Defaults to nil.

  • Global attributes are accepted. HTML attributes forwarded to the <td> element.

Slots

  • view (required) - Content shown when the row is NOT in edit mode (read view).
  • edit (required) - Input or select shown when the row IS in edit mode (edit view).

editable_row(assigns)

Renders a <tr> wrapper that applies edit-mode visual styling.

When editing={true}:

  • Adds a subtle bg-muted/20 background
  • Adds ring-1 ring-inset ring-primary/30 to signal an active edit session
  • Sets data-editing="true" for CSS or JavaScript targeting

Example

<.editable_row editing={@editing_id == user.id}>
  <.editable_cell editing={@editing_id == user.id}>
    <:view>{user.name}</:view>
    <:edit><input ... /></:edit>
  </.editable_cell>
  <.editable_row_actions row_id={to_string(user.id)} />
</.editable_row>

Attributes

  • editing (:boolean) - When true, applies an edit-mode background tint and a primary ring outline to the row. Set to false for the default read view.

    Defaults to false.

  • class (:string) - Additional CSS classes for the <tr>. Defaults to nil.

  • Global attributes are accepted. HTML attributes forwarded to the <tr> element (e.g. id).

Slots

editable_row_actions(assigns)

Renders a <td> containing Save and Cancel buttons for an editing row.

The Save button is styled as a primary action. When saving={true} it becomes dimmed to signal an in-flight request. The Cancel button is a ghost action that discards changes.

Example

<.editable_row_actions
  row_id={to_string(user.id)}
  saving={@saving_id == user.id}
  on_save="save_row"
  on_cancel="cancel_edit"
/>

Attributes

  • on_save (:string) - phx-click event fired when the Save button is clicked. Receives phx-value-id set to row_id.

    Defaults to "save_row".

  • on_cancel (:string) - phx-click event fired when the Cancel button is clicked. Receives phx-value-id set to row_id.

    Defaults to "cancel_edit".

  • row_id (:string) (required) - Row identifier sent as phx-value-id on both Save and Cancel clicks.

  • saving (:boolean) - When true, the Save button is dimmed and pointer-events are disabled. Defaults to false.

  • class (:string) - Additional CSS classes for the <td>. Defaults to nil.