Corex.Tabs (Corex v0.1.0-alpha.24)

View Source

Phoenix implementation of Zag.js Tabs.

Examples

List

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.

<.tabs
  class="tabs"
  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."]
  ])}
/>

List Custom

Similar to List but render custom trigger and content slots that will be used for all items.

Use :trigger and :content slots to customize the rendering. Each slot receives the item data.

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

Custom

Render custom trigger and content slots for each tab item manually.

Use :trigger slot for the tab button and :content slot for the tab panel content. Each slot accepts a value attribute to identify the tab item.

<.tabs id="my-tabs" value="duis" class="tabs">
  <:trigger value="lorem">
    Lorem ipsum dolor sit amet
  </:trigger>
  <:content value="lorem">
    Consectetur adipiscing elit. Sed sodales ullamcorper tristique. Proin quis risus feugiat tellus iaculis fringilla.
  </:content>
  <:trigger value="duis">
    Duis dictum gravida odio ac pharetra?
  </:trigger>
  <:content value="duis">
    Nullam eget vestibulum ligula, at interdum tellus. Quisque feugiat, dui ut fermentum sodales, lectus metus dignissim ex.
  </:content>
  <:trigger value="donec" disabled>
    Donec condimentum ex mi
  </:trigger>
  <:content value="donec">
    Congue molestie ipsum gravida a. Sed ac eros luctus.
  </:content>
</.tabs>

Controlled

Render tabs 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 string.

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

defmodule MyAppWeb.TabsLive 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"""
  <.tabs controlled value={@value} on_value_change="on_value_change" class="tabs">
    <:trigger value="lorem">
      Lorem ipsum dolor sit amet
    </:trigger>
    <:content value="lorem">
      Consectetur adipiscing elit. Sed sodales ullamcorper tristique. Proin quis risus feugiat tellus iaculis fringilla.
    </:content>
    <:trigger value="duis">
      Duis dictum gravida odio ac pharetra?
    </:trigger>
    <:content value="duis">
      Nullam eget vestibulum ligula, at interdum tellus. Quisque feugiat, dui ut fermentum sodales, lectus metus dignissim ex.
    </:content>
  </.tabs>
"""
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.Tabs.tabs_skeleton/1 to render a loading or error state

defmodule MyAppWeb.TabsAsyncLive do
use MyAppWeb, :live_view

def mount(_params, _session, socket) do
  socket =
    socket
    |> assign_async(:tabs, 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,
       %{
         tabs: %{
           items: items,
           value: "duis"
         }
       }}
    end)

  {:ok, socket}
end

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

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

      <.tabs
        id="async-tabs"
        class="tabs"
        items={tabs.items}
        value={tabs.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.Tabs.set_value("my-tabs", "item-1")}>
  Open Item 1
</button>

Server-side

def handle_event("open_item", _, socket) do
  {:noreply, Corex.Tabs.set_value(socket, "my-tabs", "item-1")}
end

Styling

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"] {}

If you wish to use the default Corex styling, you can use the class tabs on the component. This requires to install mix corex.design first and import the component css file.

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

You can then use modifiers

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

Learn more about modifiers and Corex Design

Summary

Components

Renders a tabs component.

Renders the tabs content area.

Renders a loading skeleton for the tabs component.

Renders the tabs trigger button.

API

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

Sets the tabs value from server-side. Pushes a LiveView 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.
  • 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".
  • 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

  • trigger - Accepts attributes:
    • value (:string) - The value of the trigger, useful in controlled mode and for API to identify the item.
    • disabled (:boolean) - Whether the trigger is disabled.
  • content - Accepts attributes:
    • value (:string) - The value of the content, must match the corresponding trigger value.
    • disabled (:boolean) - Whether the content is disabled.

tabs_content(assigns)

Renders the tabs content area.

Attributes

  • item (:map) (required)

Slots

  • inner_block (required)

tabs_skeleton(assigns)

Renders a loading skeleton for the tabs component.

Attributes

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

Slots

  • trigger
  • indicator
  • content

tabs_trigger(assigns)

Renders the tabs trigger button.

Attributes

  • item (:map) (required)

Slots

  • inner_block (required)

API

set_value(tabs_id, value)

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

Examples

<button phx-click={Corex.Tabs.set_value("my-tabs", "item-1")}>
  Open Item 1
</button>

<button phx-click={Corex.Tabs.set_value("my-tabs", nil)}>
  Close all Tabs
</button>

set_value(socket, tabs_id, value)

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

Examples

def handle_event("open_item", _params, socket) do
  socket = Corex.Tabs.set_value(socket, "my-tabs", "item-1")
  {:noreply, socket}
end

def handle_event("close_tabs", _params, socket) do
  socket = Corex.Tabs.set_value(socket, "my-tabs", nil)
  {:noreply, socket}
end