Corex.Avatar (Corex v0.1.0-beta.5)

View Source

Phoenix implementation of Zag.js Avatar.

Examples

Basic

<.avatar id="avatar" src="/me.jpg" class="avatar">
  <:fallback>JD</:fallback>
</.avatar>

Custom fallback with :let (:value slot)

Same idea as the angle slider value_text slot: override the fallback body and receive the current src as value.

<.avatar id="avatar" src="/me.jpg" class="avatar">
  <:value :let={value}>{if value, do: "JD", else: "?"}</:value>
</.avatar>

When the :value slot is omitted, <:fallback> is used.

pending vs the hooked avatar

With pending={true}, the component does not mount phx-hook="Avatar", does not run Zag, and does not render an <img>. Assigns such as src have no visible effect until you re-render with pending={false}. The :loading slot is only used in that pending branch (custom markup or avatar_skeleton/1 when empty); it is not a replacement for the hooked avatar’s own loading UI.

Async loading

<.async_result :let={profile} assign={@profile}>
  <:loading>
    <.avatar_skeleton class="avatar" />
  </:loading>
  <:failed>Could not load.</:failed>
  <.avatar id="user-avatar" src={profile.avatar_url} class="avatar">
    <:fallback>{profile.initials}</:fallback>
  </.avatar>
</.async_result>

Pending without async_result

<.avatar pending class="avatar">
  <:loading><span class="text-sm">Loading…</span></:loading>
</.avatar>

When pending is true and the :loading slot is empty, avatar_skeleton/1 is used.

API

The API targets one avatar via its DOM id (the same id you pass to avatar/1).

For loaded, use respond_to: :server | :client | :both to control whether the response is pushed to LiveView, dispatched as a DOM event, or both.

<.action phx-click={Corex.Avatar.set_src("my-avatar", "https://example.com/a.png")}>Set image</.action>
<.action phx-click={Corex.Avatar.loaded("my-avatar")}>Read loaded</.action>

Events

User interaction and imperative API use different channels. See also on_status_change / on_status_change_client on avatar/1.

User interaction

When phx-hook="Avatar" is active, Zag invokes on_status_change (server) and on_status_change_client (client CustomEvent type you set). Params / event.detail include %{"id" => dom_id, "status" => "loaded" | "error"} (string keys from the server; camelCase in JS detail as emitted by the hook).

Imperative API (LiveView helpers and client DOM)

From LiveView, use Corex.Avatar.set_src/3 and loaded/3. They use push_event/3 to the hook; optional respond_to controls where the answer goes for loaded/3.

From the client, dispatch CustomEvents on the hook root (e.g. #my-avatar):

Dispatch (type)detail
corex:avatar:set-srcsrc - image URL string
corex:avatar:loadedoptional respond_to: "server", "client", or "both"

Responses to LiveView (push_event from the hook; handle in handle_event/3):

  • avatar_loaded_response - %{"id" => ..., "loaded" => boolean}

Responses to the DOM (listen on the hook root element):

  • avatar-loaded - detail with id and loaded

Styling

Use data attributes to target elements:

[data-scope="avatar"][data-part="root"] {}
[data-scope="avatar"][data-part="image"] {}
[data-scope="avatar"][data-part="fallback"] {}
[data-scope="avatar"][data-part="skeleton"] {}

If you wish to use the default Corex styling, you can use the class avatar on the component. This requires to install Mix.Tasks.Corex.Design first and import the component css file.

@import "../corex/main.css";
@import "../corex/tokens/themes/neo/light.css";
@import "../corex/components/avatar.css";

You can then use modifiers

<.avatar class="avatar avatar--accent avatar--lg">
  <:fallback>JD</:fallback>
</.avatar>

Summary

Components

Static loading placeholder for use with <.async_result> or when pending is true without a :loading slot.

API

Requests whether the avatar image is loaded from the browser. Returns a Phoenix.LiveView.JS command.

Requests loaded state from the client. Pushes a LiveView event handled by the hook.

Sets the avatar image URL from the client. Returns a Phoenix.LiveView.JS command.

Sets the avatar image URL from the server. Pushes a LiveView event handled by the hook.

Components

avatar(assigns)

Attributes

  • id (:string) - The id of the avatar.
  • src (:string) - Image source URL. Defaults to nil.
  • alt (:string) - Alternative text for the image. Defaults to "".
  • dir (:string) - Direction. Defaults to nil. Must be one of nil, "ltr", or "rtl".
  • pending (:boolean) - When true, renders only the loading UI (:loading slot or avatar_skeleton/1), without the Avatar hook. Defaults to false.
  • on_status_change (:string) - Server event when image load status changes. Defaults to nil.
  • on_status_change_client (:string) - Client event when image load status changes. Defaults to nil.
  • Global attributes are accepted.

Slots

  • loading - Custom loading content when pending is true. Overrides default avatar_skeleton/1. Accepts attributes:
    • class (:string)
  • fallback - Content for the fallback part when the image is absent or not yet shown. Accepts attributes:
    • class (:string)
  • value - Optional replacement for :fallback inner content. Use :let={value} - value is the image src (or nil). Accepts attributes:
    • class (:string)

avatar_skeleton(assigns)

Static loading placeholder for use with <.async_result> or when pending is true without a :loading slot.

Attributes

  • Global attributes are accepted.

API

loaded(avatar_id)

Requests whether the avatar image is loaded from the browser. Returns a Phoenix.LiveView.JS command.

Options: :respond_to - :server (default, avatar_loaded_response only), :both, or :client (avatar-loaded DOM only).

Examples

<.action phx-click={Corex.Avatar.loaded("my-avatar")} class="button button--sm">Loaded</.action>
<.action phx-click={Corex.Avatar.loaded("my-avatar", respond_to: :client)} class="button button--sm">
  Loaded (client)
</.action>

loaded(socket, avatar_id, opts \\ [])

Requests loaded state from the client. Pushes a LiveView event handled by the hook.

See loaded/2 for :respond_to.

Examples

def handle_event("avatar_loaded_response", %{"id" => id, "loaded" => loaded}, socket) do
  {:noreply, assign(socket, :avatar_loaded, {id, loaded})}
end

set_src(avatar_id, src)

Sets the avatar image URL from the client. Returns a Phoenix.LiveView.JS command.

Examples

<.action phx-click={Corex.Avatar.set_src("my-avatar", "https://example.com/x.png")} class="button button--sm">
  Set src
</.action>

set_src(socket, avatar_id, src)

Sets the avatar image URL from the server. Pushes a LiveView event handled by the hook.

Examples

def handle_event("set_avatar", %{"url" => url}, socket) do
  {:noreply, Corex.Avatar.set_src(socket, "my-avatar", url)}
end

Functions

loaded(avatar_id, opts)