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
endAsync
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
endAPI 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"])}
endStyling
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
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
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 tofalse.collapsible(:boolean) - Whether the accordion is collapsible. Defaults totrue.multiple(:boolean) - Whether the accordion allows multiple items to be selected. Defaults totrue.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 tonil. Must be one ofnil,"ltr", or"rtl".on_value_change(:string) - The server event name when the value change. Defaults tonil.on_value_change_client(:string) - The client event name when the value change. Defaults tonil.on_focus_change(:string) - The server event name when the focus change. Defaults tonil.on_focus_change_client(:string) - The client event name when the focus change. Defaults tonil.- 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)
Renders a loading skeleton for the accordion component.
Attributes
count(:integer) - Defaults to3.- Global attributes are accepted.
Slots
trigger- Accepts attributes:class(:string)
indicator- Accepts attributes:class(:string)
content- Accepts attributes:class(:string)
API
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>
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