Hooks section DSL definition for table configuration.
Defines lifecycle callbacks for table events.
Three layers
Global lifecycle — fires for every event of a kind (
before_delete,after_delete,on_realtime,on_filter, …). These keep their existing behavior.Per-action observers — fire alongside the built-in handler for a specific row or bulk action, keyed by the action's
name. They cannot replace the handler; they observe and decorate it.before_row_action :name, fn record, state -> ... endafter_row_action :name, fn result, state -> ... endon_row_action_success :name, fn result, state[, socket] -> socket endon_row_action_error :name, fn reason, state[, socket] -> socket endbefore_bulk_action :name, fn ids, state -> ... endafter_bulk_action :name, fn result, state -> ... endon_bulk_action_success :name, fn result, state[, socket] -> socket endon_bulk_action_error :name, fn errors, state[, socket] -> socket end
The
on_*_success/on_*_errorhooks accept arity 2 or 3. Use arity 3 when you need the live socket for full manual control (e.g. to callDataLoader.apply_archive_status/3,Phoenix.LiveView.push_navigate/2,put_flash/3, etc). Arity 2 is fine for log-only side effects.A list of action names is also accepted to share one hook across actions:
before_row_action [:unarchive, :restore], fn ... end.Full overrides — replace the built-in handler entirely. These are the same runtime as the legacy
{:on_event, name}/{:on_bulk_action, name}keys; the DSL aliases below are the documented form.override_row_action :name, fn payload, state -> {:ok, state} endoverride_bulk_action :name, fn ids, state -> {:ok, state} end
Built-in state-transition rules — opt-in flags for common UX transitions, declared directly inside
hooks do … end:hooks do
switch_to_active_on_empty_archive true clear_selection_after_bulk true reset_page_on_empty_current_page true redirect_on_empty "/dashboard"end
Return Values
Most hooks can return:
socket- Continue with modified socket{:cont, socket}- Explicitly continue with modified socket{:halt, socket}- Stop the action (e.g., skip realtime update, cancel expand)
Example
hooks do
on_realtime fn notification, socket ->
if notification.data.created_by_id == socket.assigns.current_user.id do
{:halt, socket}
else
{:cont, put_flash(socket, :info, "New record added!")}
end
end
before_row_action :unarchive, fn record, state ->
if record.locked?, do: {:halt, {:error, "locked"}}, else: :ok
end
after_bulk_action :unarchive, fn _result, _state -> :ok end
switch_to_active_on_empty_archive true
end