Corex.Tabs (Corex v0.1.2)

View Source

Phoenix implementation of Zag.js Tabs.

Anatomy

Basic

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

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

You can specify disabled for each item.

<.tabs
  class="tabs"
  items={Corex.Content.new([
    [label: "Lorem", content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique."],
    [label: "Duis", content: "Nullam eget vestibulum ligula, at interdum tellus."],
    [label: "Donec", content: "Congue molestie ipsum gravida a. Sed ac eros luctus."]
  ])}
/>

With indicator

Set the boolean indicator attribute to render the single shared item indicator (Zag) after the tab triggers.

<.tabs
  class="tabs"
  indicator
  items={Corex.Content.new([
    [value: "lorem", label: "Lorem", content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique."],
    [label: "Duis", content: "Nullam eget vestibulum ligula, at interdum tellus."],
    [value: "donec", label: "Donec", content: "Congue molestie ipsum gravida a. Sed ac eros luctus."]
  ])}
>
</.tabs>

Custom

Use :trigger and :content together to fully customize how each item is rendered. Render icons or extras inside each :trigger slot. Use :let={item} on slots to access the item and its data (including meta for per-item customization). Use tabs_indicator once inside tabs_list when you need the shared indicator in compound mode.

<.tabs
  class="tabs"
  value="lorem"
  items={Corex.Content.new([
    [value: "lorem", label: "Lorem", content: "Consectetur adipiscing elit. Sed sodales ullamcorper tristique.", meta: %{indicator: "hero-chevron-right"}],
    [label: "Duis", content: "Nullam eget vestibulum ligula, at interdum tellus.", meta: %{indicator: "hero-chevron-right"}],
    [value: "donec", label: "Donec", content: "Congue molestie ipsum gravida a. Sed ac eros luctus."]
  ])}
>
  <:trigger :let={item}>
    {item.label}
  </:trigger>
  <:content :let={item}>
    {item.content}
  </:content>
</.tabs>

API

Requires a stable id on <.tabs>.

FunctionActionReturns
set_value/2Set active tab (client)%Phoenix.LiveView.JS{}
set_value/3Set active tab (server)socket

Events

Pick an event name and pass it to on_* on <.tabs>.

Server events

EventWhenPayload
on_value_change="tabs_value_changed"Active tab changes%{"id" => id, "value" => value}
on_focus_change="tabs_focus_changed"Focused tab changes%{"id" => id, "value" => value}

Client events

EventWhenevent.detail
on_value_change_client="tabs-value-changed"Active tab changesid, value
on_focus_change_client="tabs-focus-changed"Focused tab changesid, value

Patterns

Controlled

<.tabs
  controlled
  value={@value}
  on_value_change="tabs_value_changed"
  class="tabs"
  items={
    Corex.Content.new([
      %{value: "lorem", label: "Lorem", content: "Consectetur adipiscing elit."},
      %{value: "duis", label: "Duis", content: "Nullam eget vestibulum ligula."}
    ])
  }
/>
def handle_event("tabs_value_changed", %{"value" => value}, socket) do
  {:noreply, assign(socket, :value, value)}
end

Async

<.async_result :let={tabs} assign={@tabs}>
  <:loading><.tabs_skeleton count={3} class="tabs" /></:loading>
  <:failed>Could not load tabs.</:failed>
  <.tabs class="tabs" items={tabs.items} value={tabs.value} />
</.async_result>
socket =
  assign_async(socket, :tabs, fn ->
    {:ok,
     %{
       tabs: %{
         items:
           Corex.Content.new([
             %{value: "lorem", label: "Lorem", content: "Consectetur adipiscing elit."},
             %{value: "duis", label: "Duis", content: "Nullam eget vestibulum ligula."}
           ]),
         value: "duis"
       }
     }}
  end)

Style

Use data attributes to target elements:

[data-scope="tabs"][data-part="root"] {}
[data-scope="tabs"][data-part="item"] {}
[data-scope="tabs"][data-part="item-trigger"] {}
[data-scope="tabs"][data-part="item-content"] {}
[data-scope="tabs"][data-part="item-indicator"] {}
@import "../corex/main.css";
@import "../corex/tokens/themes/neo/light.css";
@import "../corex/components/tabs.css";

Stack modifiers on the host (class on <.tabs>).

Color

ModifierClasses
Defaulttabs
Accenttabs tabs--accent
Brandtabs tabs--brand
Alerttabs tabs--alert
Infotabs tabs--info
Successtabs tabs--success

Size

ModifierClasses
SMtabs tabs--sm
MDtabs tabs--md
LGtabs tabs--lg
XLtabs tabs--xl

Summary

Components

Renders a tabs component.

Renders a loading skeleton for the tabs component.

API

Set the active tab from a control (phx-click). value is the tab item value (same as items' value).

Set the active tab from handle_event.

Components

tabs(assigns)

Renders a tabs component.

You can use either:

  • The :trigger and :content slots for manual tab definition with full control
  • The :items attribute for programmatic tab generation from a list of content items

Use Corex.Content.new/1 to create items.

When using :trigger and :content slots:

  • Each :trigger slot should have a value attribute to identify the tab
  • Each :content slot should have a matching value attribute
  • Triggers are rendered in the list, content panels are rendered outside the list

Attributes

  • id (:string) - The id of the tabs, useful for API to identify the tabs.
  • items (:list) - The items of the tabs, must be a list of content items. Defaults to nil.
  • compound (:boolean) - Enable compound mode. Use with :let={ctx} and tabs_root, tabs_list, tabs_trigger, tabs_content, tabs_indicator once inside tabs_list. Defaults to false.
  • value (:string) - The initial value or the controlled value of the tabs, must be a string. Defaults to nil.
  • controlled (:boolean) - Whether the tabs is controlled. Only in LiveView, the on_value_change event is required. Defaults to false.
  • collapsible (:boolean) - Whether the tabs is collapsible. Defaults to true.
  • multiple (:boolean) - Whether the tabs allows multiple items to be selected. Defaults to true.
  • orientation (:string) - The orientation of the tabs. Defaults to "horizontal". Must be one of "horizontal", or "vertical".
  • dir (:string) - The direction of the tabs. When nil, derived from document (html lang + config :rtl_locales). Defaults to nil. Must be one of nil, "ltr", or "rtl".
  • indicator (:boolean) - Whether to show an indicator on the trigger list. Defaults to true.
  • 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

  • inner_block - Compound mode inner content. Use with the compound attribute and :let={ctx}. ctx is a map with keys: id, values, orientation, dir.

  • trigger - Optional slot for custom trigger rendering. When provided with content, replaces default item rendering. Use :let={item} to access the item. Accepts attributes:

    • value (:string)
    • 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)
    • value (:string)

tabs_skeleton(assigns)

Renders a loading skeleton for the tabs 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)

Compounds

tabs_content(assigns)

Attributes

  • ctx (:map) (required)
  • value (:string) (required)
  • disabled (:boolean) - Defaults to false.
  • Global attributes are accepted.

Slots

  • inner_block (required)

tabs_indicator(assigns)

Attributes

  • ctx (:map) (required)
  • Global attributes are accepted.

Slots

  • inner_block

tabs_list(assigns)

Attributes

  • ctx (:map) (required)
  • Global attributes are accepted.

Slots

  • inner_block (required)

tabs_root(assigns)

Attributes

  • ctx (:map) (required)
  • Global attributes are accepted.

Slots

  • inner_block (required)

tabs_trigger(assigns)

Attributes

  • ctx (:map) (required)
  • value (:string) (required)
  • disabled (:boolean) - Defaults to false.
  • Global attributes are accepted.

Slots

  • inner_block (required)

API

set_value(tabs_id, value)

Set the active tab from a control (phx-click). value is the tab item value (same as items' value).

<.action phx-click={Corex.Tabs.set_value("my-tabs", "lorem")}>Lorem</.action>
<.tabs
  id="my-tabs"
  class="tabs"
  items={Corex.Content.new([
    [value: "lorem", label: "Lorem", content: "A."],
    [value: "duis", label: "Duis", content: "B."]
  ])}
/>
document.getElementById("my-tabs")?.dispatchEvent(
  new CustomEvent("corex:tabs:set-value", {
    bubbles: false,
    detail: { value: "lorem" },
  })
);

set_value(socket, tabs_id, value)

Set the active tab from handle_event.

<.action phx-click="pick_tab" phx-value-value="lorem">Lorem</.action>
<.tabs
  id="my-tabs"
  class="tabs"
  items={Corex.Content.new([
    [value: "lorem", label: "Lorem", content: "A."],
    [value: "duis", label: "Duis", content: "B."]
  ])}
/>
def handle_event("pick_tab", %{"value" => value}, socket) do
  {:noreply, Corex.Tabs.set_value(socket, "my-tabs", value)}
end