Corex.Tabs (Corex v0.1.0-alpha.24)
View SourcePhoenix 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")}
endStyling
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
Renders a tabs component.
You can use either:
- The
:triggerand:contentslots for manual tab definition with full control - The
:itemsattribute 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
:triggerslot should have avalueattribute to identify the tab - Each
:contentslot should have a matchingvalueattribute - 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 tonil.value(:string) - The initial value or the controlled value of the tabs, must be a string. Defaults tonil.controlled(:boolean) - Whether the tabs is controlled. Only in LiveView, the on_value_change event is required. Defaults tofalse.collapsible(:boolean) - Whether the tabs is collapsible. Defaults totrue.multiple(:boolean) - Whether the tabs allows multiple items to be selected. Defaults totrue.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 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
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.
Renders the tabs content area.
Attributes
item(:map) (required)
Slots
inner_block(required)
Renders a loading skeleton for the tabs component.
Attributes
count(:integer) - Defaults to3.- Global attributes are accepted.
Slots
triggerindicatorcontent
Renders the tabs trigger button.
Attributes
item(:map) (required)
Slots
inner_block(required)
API
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>
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