Corex.Accordion (Corex v0.1.0-alpha.33)

View Source

Phoenix implementation of Zag.js Accordion.

Examples

Basic

You can use Corex.Content.new/1 to create a list of content items.

The id for each item is optional and will be auto-generated if not provided.

You can specify disabled for each item.

<.accordion
  class="accordion"
  items={Corex.Content.new([
    [trigger: "Lorem ipsum dolor sit amet", content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique."],
    [trigger: "Duis dictum gravida odio ac pharetra?", content: "Nullam eget vestibulum ligula, at interdum tellus."],
    [trigger: "Donec condimentum ex mi", content: "Congue molestie ipsum gravida a. Sed ac eros luctus."]
  ])}
/>

With indicator

Use the optional :indicator slot to add an icon after each trigger.

<.accordion
  class="accordion"
  items={Corex.Content.new([
    [
      id: "lorem",
      trigger: "Lorem ipsum dolor sit amet",
      content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique."
    ],
    [
      trigger: "Duis dictum gravida odio ac pharetra?",
      content: "Nullam eget vestibulum ligula, at interdum tellus."
    ],
    [
      id: "donec",
      trigger: "Donec condimentum ex mi",
      content: "Congue molestie ipsum gravida a. Sed ac eros luctus."
    ]
  ])}
>
  <:indicator>
    <.heroicon name="hero-chevron-right" />
  </:indicator>
</.accordion>

You can use switching indicator using css classes state-open and state-closed on the indicator icon. This classes simply target the data-state attribute of the item indicator.

  <.accordion
  class="accordion"
  items={
    Corex.Content.new([
      [
        id: "lorem",
        trigger: "Lorem ipsum dolor sit amet",
        content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique."
      ],
      [
        trigger: "Duis dictum gravida odio ac pharetra?",
        content: "Nullam eget vestibulum ligula, at interdum tellus."
      ],
      [
        id: "donec",
        trigger: "Donec condimentum ex mi",
        content: "Congue molestie ipsum gravida a. Sed ac eros luctus."
      ]
    ])
  }
>
  <:indicator>
    <.heroicon name="hero-plus" class="state-closed"/>
    <.heroicon name="hero-minus" class="state-open"/>
  </:indicator>
</.accordion>

Custom

Use :trigger and :content together to fully customize how each item is rendered. Add the :indicator slot to show an icon after each trigger. Use :let={item} on slots to access the item and its data (including meta for per-item customization).

<.accordion
  class="accordion"
  items={
    Corex.Content.new([
      [
        id: "lorem",
        trigger: "Lorem ipsum dolor sit amet",
        content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique.",
        meta: %{indicator: "hero-arrow-long-right", icon: "hero-chat-bubble-left-right"}
      ],
      [
        trigger: "Duis dictum gravida ?",
        content: "Nullam eget vestibulum ligula, at interdum tellus.",
        meta: %{indicator: "hero-chevron-right", icon: "hero-device-phone-mobile"}
      ],
      [
        id: "donec",
        trigger: "Donec condimentum ex mi",
        content: "Congue molestie ipsum gravida a. Sed ac eros luctus.",
        disabled: true,
        meta: %{indicator: "hero-chevron-double-right", icon: "hero-phone"}
      ]
    ])
  }
>
  <:trigger :let={item}>
    <.heroicon name={item.data.meta.icon} />{item.data.trigger}
  </:trigger>
  <:content :let={item}>{item.data.content}</:content>
  <:indicator :let={item}>
    <.heroicon name={item.data.meta.indicator} />
  </:indicator>
</.accordion>

Controlled

Render an accordion controlled by the server.

You must use the on_value_change event to update the value on the server and pass the value as a list of strings.

The event will receive the value as a map with the key value and the id of the accordion.

defmodule MyAppWeb.AccordionLive do
  use MyAppWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, assign(socket, :value, ["lorem"])}
  end

  def handle_event("on_value_change", %{"value" => value}, socket) do
    {:noreply, assign(socket, :value, value)}
  end

  def render(assigns) do
    ~H"""
    <.accordion
      controlled
      value={@value}
      on_value_change="on_value_change"
      class="accordion"
      items={Corex.Content.new([
        [id: "lorem", trigger: "Lorem ipsum dolor sit amet", content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique. Proin quis risus feugiat tellus iaculis fringilla."],
        [id: "duis", trigger: "Duis dictum gravida odio ac pharetra?", content: "Nullam eget vestibulum ligula, at interdum tellus. Quisque feugiat, dui ut fermentum sodales, lectus metus dignissim ex."]
      ])}
    />
    """
  end
end

Async

When the initial props are not available on mount, you can use the Phoenix.LiveView.assign_async function to assign the props asynchronously

You can use the optional Corex.Accordion.accordion_skeleton/1 to render a loading or error state

defmodule MyAppWeb.AccordionAsyncLive do
  use MyAppWeb, :live_view

  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign_async(:accordion, fn ->
        Process.sleep(1000)

        items = Corex.Content.new([
          [
            id: "lorem",
            trigger: "Lorem ipsum dolor sit amet",
            content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique.",
            disabled: true
          ],
          [
            id: "duis",
            trigger: "Duis dictum gravida odio ac pharetra?",
            content: "Nullam eget vestibulum ligula, at interdum tellus."
          ],
          [
            id: "donec",
            trigger: "Donec condimentum ex mi",
            content: "Congue molestie ipsum gravida a. Sed ac eros luctus."
          ]
        ])

        {:ok,
         %{
           accordion: %{
             items: items,
             value: ["duis", "donec"]
           }
         }}
      end)

    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <.async_result :let={accordion} assign={@accordion}>
      <:loading>
        <.accordion_skeleton count={3} class="accordion" />
      </:loading>

      <:failed>
        there was an error loading the accordion
      </:failed>

      <.accordion
        id="async-accordion"
        class="accordion"
        items={accordion.items}
        value={accordion.value}
      />
    </.async_result>
    """
  end
end

API Control

In order to use the API, you must use an id on the component

Client-side

<button phx-click={Corex.Accordion.set_value("my-accordion", ["item-1"])}>
  Open Item 1
</button>

Server-side

def handle_event("open_item", _, socket) do
  {:noreply, Corex.Accordion.set_value(socket, "my-accordion", ["item-1"])}
end

Styling

Use data attributes to target elements:

[data-scope="accordion"][data-part="root"] {}
[data-scope="accordion"][data-part="item"] {}
[data-scope="accordion"][data-part="item-trigger"] {}
[data-scope="accordion"][data-part="item-content"] {}
[data-scope="accordion"][data-part="item-indicator"] {}

If you wish to use the default Corex styling, you can use the class accordion 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/accordion.css";

You can then use modifiers

<.accordion class="accordion accordion--accent accordion--lg">

Learn more about modifiers and Corex Design

Summary

Components

Renders an accordion component.

Renders a loading skeleton for the accordion component.

API

Sets the accordion value from client-side. Returns a Phoenix.LiveView.JS command.

Sets the accordion value from server-side. Pushes a LiveView event.

Components

accordion(assigns)

Renders an accordion component.

Pass items as a list of %Corex.Content.Item{} structs. Use the optional :indicator slot to add content after each trigger. Use :trigger and :content together to fully customize item rendering.

Each item MUST be a %Corex.Content.Item{} struct with:

  • :id (optional, auto-generated) - unique identifier for the item
  • :trigger (required) - content for the trigger button
  • :content (required) - content for the accordion panel
  • :disabled (optional, default: false) - whether the item is disabled
  • :meta (optional) - additional metadata for the item

Attributes

  • id (:string) - The id of the accordion, useful for API to identify the accordion.
  • items (:list) (required) - The items of the accordion, must be a list of %Corex.Content.Item{} structs.
  • value (:list) - The initial value or the controlled value of the accordion, must be a list of strings. Defaults to [].
  • controlled (:boolean) - Whether the accordion is controlled. Only in LiveView, the on_value_change event is required. Defaults to false.
  • collapsible (:boolean) - Whether the accordion is collapsible. Defaults to true.
  • multiple (:boolean) - Whether the accordion allows multiple items to be selected. Defaults to true.
  • orientation (:string) - The orientation of the accordion. Defaults to "vertical". Must be one of "horizontal", or "vertical".
  • dir (:string) - The direction of the accordion. When nil, derived from document (html lang + config :rtl_locales). Defaults to nil. Must be one of nil, "ltr", or "rtl".
  • on_value_change (:string) - The server event name when the value change. Defaults to nil.
  • on_value_change_client (:string) - The client event name when the value change. Defaults to nil.
  • on_focus_change (:string) - The server event name when the focus change. Defaults to nil.
  • on_focus_change_client (:string) - The client event name when the focus change. Defaults to nil.
  • Global attributes are accepted.

Slots

  • indicator - Optional slot for content after each trigger. Use :let={item} for per-item customization. Accepts attributes:
    • class (:string)
  • trigger - Optional slot for custom trigger rendering. When provided with content, replaces default item rendering. Use :let={item} to access the item. Accepts attributes:
    • class (:string)
  • content - Optional slot for custom content rendering. When provided with trigger, replaces default item rendering. Use :let={item} to access the item. Accepts attributes:
    • class (:string)

accordion_skeleton(assigns)

Renders a loading skeleton for the accordion component.

Attributes

  • count (:integer) - Defaults to 3.
  • Global attributes are accepted.

Slots

  • trigger - Accepts attributes:
    • class (:string)
  • indicator - Accepts attributes:
    • class (:string)
  • content - Accepts attributes:
    • class (:string)

API

set_value(accordion_id, value)

Sets the accordion value from client-side. Returns a Phoenix.LiveView.JS command.

Examples

<button phx-click={Corex.Accordion.set_value("my-accordion", ["item-1"])}>
  Open Item 1
</button>

set_value(socket, accordion_id, value)

Sets the accordion value from server-side. Pushes a LiveView event.

Examples

def handle_event("open_item", _params, socket) do
  socket = Corex.Accordion.set_value(socket, "my-accordion", ["item-1"])
  {:noreply, socket}
end