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>.
| Function | Action | Returns |
|---|---|---|
set_value/2 | Set active tab (client) | %Phoenix.LiveView.JS{} |
set_value/3 | Set active tab (server) | socket |
Events
Pick an event name and pass it to on_* on <.tabs>.
Server events
| Event | When | Payload |
|---|---|---|
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
| Event | When | event.detail |
|---|---|---|
on_value_change_client="tabs-value-changed" | Active tab changes | id, value |
on_focus_change_client="tabs-focus-changed" | Focused tab changes | id, 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)}
endAsync
<.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
| Modifier | Classes |
|---|---|
| Default | tabs |
| Accent | tabs tabs--accent |
| Brand | tabs tabs--brand |
| Alert | tabs tabs--alert |
| Info | tabs tabs--info |
| Success | tabs tabs--success |
Size
| Modifier | Classes |
|---|---|
| SM | tabs tabs--sm |
| MD | tabs tabs--md |
| LG | tabs tabs--lg |
| XL | tabs tabs--xl |
Summary
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
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.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 tofalse.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".indicator(:boolean) - Whether to show an indicator on the trigger list. Defaults totrue.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
inner_block- Compound mode inner content. Use with thecompoundattribute and:let={ctx}.ctxis 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)
Renders a loading skeleton for the tabs 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)
Compounds
Attributes
ctx(:map) (required)value(:string) (required)disabled(:boolean) - Defaults tofalse.- Global attributes are accepted.
Slots
inner_block(required)
Attributes
ctx(:map) (required)- Global attributes are accepted.
Slots
inner_block
Attributes
ctx(:map) (required)- Global attributes are accepted.
Slots
inner_block(required)
Attributes
ctx(:map) (required)- Global attributes are accepted.
Slots
inner_block(required)
Attributes
ctx(:map) (required)value(:string) (required)disabled(:boolean) - Defaults tofalse.- Global attributes are accepted.
Slots
inner_block(required)
API
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 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