Corex.Collapsible (Corex v0.1.0-beta.1)

View Source

Phoenix implementation of Zag.js Collapsible.

Examples

Basic

<.collapsible id="my-collapsible">
  <:trigger>Toggle Content</:trigger>
  <:content>
    This content can be collapsed and expanded.
  </:content>
</.collapsible>

With opened and closed surfaces

Optional :closed and :opened slots render after the trigger label (same button). Use one chevron in :closed and default CSS rotates it when open (like Accordion). Use both slots to swap different markup when open vs closed.

<.collapsible id="my-collapsible">
  <:trigger>Toggle Content</:trigger>
  <:closed>
    <.heroicon name="hero-chevron-down" />
  </:closed>
  <:content>
    This content can be collapsed and expanded.
  </:content>
</.collapsible>

Custom with :let

Use :let={collapsible} on :trigger, :content, :closed, or :opened to access collapsible.open and collapsible.disabled.

<.collapsible id="my-collapsible">
  <:trigger :let={collapsible}>
    {if collapsible.open, do: "Collapse", else: "Expand"}
  </:trigger>
  <:content :let={_c}>Panel body</:content>
  <:closed :let={collapsible}>
    <.heroicon name={if collapsible.open, do: "hero-minus", else: "hero-plus"} />
  </:closed>
</.collapsible>

Controlled

<.collapsible
  id="my-collapsible"
  controlled
  open={@collapsible_open}
  on_open_change="collapsible_changed">
  <:trigger>Toggle Content</:trigger>
  <:content>
    This content can be collapsed and expanded.
  </:content>
</.collapsible>
def handle_event("collapsible_changed", %{"open" => open}, socket) do
  {:noreply, assign(socket, :collapsible_open, open)}
end

API Control

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

Client-side

<button phx-click={Corex.Collapsible.set_open("my-collapsible", true)}>
  Open
</button>

Server-side

def handle_event("open_collapsible", _, socket) do
  {:noreply, Corex.Collapsible.set_open(socket, "my-collapsible", true)}
end

Styling

Target parts with data-scope="collapsible" and data-part:

[data-scope="collapsible"][data-part="root"] {}
[data-scope="collapsible"][data-part="trigger"] {}
[data-scope="collapsible"][data-part="content"] {}
[data-scope="collapsible"][data-part="closed"] {}
[data-scope="collapsible"][data-part="opened"] {}

Root, trigger, and content have data-state="open" or data-state="closed". When the trigger is focused, data-focus is set on root, trigger, and content.

The content part exposes --height, --width, --collapsed-height, and --collapsed-width for animations. Example:

[data-scope="collapsible"][data-part="content"] {
  overflow: hidden;
}
[data-scope="collapsible"][data-part="content"][data-state="open"] {
  animation: expand 110ms cubic-bezier(0, 0, 0.38, 0.9);
}
[data-scope="collapsible"][data-part="content"][data-state="closed"] {
  animation: collapse 110ms cubic-bezier(0, 0, 0.38, 0.9);
}
@keyframes expand {
  from { height: var(--collapsed-height, 0); }
  to { height: var(--height); }
}
@keyframes collapse {
  from { height: var(--height); }
  to { height: var(--collapsed-height, 0); }
}

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

You can then use modifiers

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

Summary

Components

Renders a collapsible component.

API

Sets the collapsible open state from client-side. Returns a Phoenix.LiveView.JS command.

Sets the collapsible open state from server-side. Pushes a LiveView event.

Components

collapsible(assigns)

Renders a collapsible component.

Requires :trigger and :content slots. Optional :closed and :opened slots add visual surfaces after the trigger label (Connect data-part only, no Zag props). Use :let={collapsible} on slots to access collapsible.open and collapsible.disabled.

Attributes

  • id (:string) - The id of the collapsible, useful for API to identify the collapsible.
  • open (:boolean) - The initial open state or the controlled open state. Defaults to false.
  • controlled (:boolean) - Whether the collapsible is controlled. Only in LiveView, the on_open_change event is required. Defaults to false.
  • disabled (:boolean) - Whether the collapsible is disabled. Defaults to false.
  • dir (:string) - The direction of the collapsible. When nil, derived from document (html lang + config :rtl_locales). Defaults to "ltr". Must be one of "ltr", or "rtl".
  • orientation (:string) - Layout orientation for CSS. Defaults to "vertical". Must be one of "horizontal", or "vertical".
  • on_open_change (:string) - The server event name when the open state changes. Defaults to nil.
  • on_open_change_client (:string) - The client event name when the open state changes. Defaults to nil.
  • Global attributes are accepted.

Slots

  • trigger (required) - Trigger button content. Use :let={collapsible} to access open and disabled state. Accepts attributes:
    • class (:string)
  • content (required) - Expandable content. Use :let={collapsible} to access open and disabled state. Accepts attributes:
    • class (:string)
  • closed - Optional surface after the trigger, visible when closed (or use with :opened to swap content by state). Accepts attributes:
    • class (:string)
  • opened - Optional surface after the trigger, visible when open (use with :closed to swap content by state). Accepts attributes:
    • class (:string)

API

set_open(collapsible_id, open)

Sets the collapsible open state from client-side. Returns a Phoenix.LiveView.JS command.

Examples

<button phx-click={Corex.Collapsible.set_open("my-collapsible", true)}>
  Open
</button>

set_open(socket, collapsible_id, open)

Sets the collapsible open state from server-side. Pushes a LiveView event.

Examples

def handle_event("open_collapsible", _params, socket) do
  socket = Corex.Collapsible.set_open(socket, "my-collapsible", true)
  {:noreply, socket}
end

Functions

collapsible_skeleton(assigns)

Attributes

  • dir (:string) - Same as collapsible: logical direction for the skeleton root. Defaults to "ltr". Must be one of "ltr", or "rtl".
  • orientation (:string) - Same as collapsible: layout orientation for CSS. Defaults to "vertical". Must be one of "horizontal", or "vertical".
  • Global attributes are accepted.