Navigation

Tabs

Three tags make up this family: <oblyx-tab-list> is the strip, each <oblyx-tab> is one tab inside it, and each <oblyx-tab-panel> is the content that tab controls. Unlike upstream Astryx, which only tracks which tab looks selected, Oblyx's tab list also owns real panels with role="tabpanel" and the full aria-controls/aria-labelledby wiring, because a server-rendered page needs somewhere for the tab content to actually live.

Basic tabs

Apple Banana Cherry Apples are crisp and sweet. Bananas are soft and mild. Cherries are tart and small.
HTMLKotlin
<oblyx-tab-list id="fruit-tabs" value="apple">
  <oblyx-tab value="apple">Apple</oblyx-tab>
  <oblyx-tab value="banana">Banana</oblyx-tab>
  <oblyx-tab value="cherry">Cherry</oblyx-tab>
</oblyx-tab-list>
<oblyx-tab-panel list="fruit-tabs" value="apple">Apples are crisp and sweet.</oblyx-tab-panel>
<oblyx-tab-panel list="fruit-tabs" value="banana">Bananas are soft and mild.</oblyx-tab-panel>
<oblyx-tab-panel list="fruit-tabs" value="cherry">Cherries are tart and small.</oblyx-tab-panel>
oblyxTabList(value = "apple") {
  attributes["id"] = "fruit-tabs"
  oblyxTab(value = "apple") { +"Apple" }
  oblyxTab(value = "banana") { +"Banana" }
  oblyxTab(value = "cherry") { +"Cherry" }
}
oblyxTabPanel(list = "fruit-tabs", value = "apple") { +"Apples are crisp and sweet." }
oblyxTabPanel(list = "fruit-tabs", value = "banana") { +"Bananas are soft and mild." }
oblyxTabPanel(list = "fruit-tabs", value = "cherry") { +"Cherries are tart and small." }

How a panel finds its list

A <oblyx-tab-panel> is a sibling of <oblyx-tab-list>, not a descendant of it: realistic markup puts the whole tab strip above the panels, the way the example above is written. Nothing in the tag names suggests that relationship, so it works the same way <label for> does: each panel's list attribute names the id of the tab list it belongs to, and the panel resolves that reference fresh every time the list's selection changes, never a cached reference. When list is omitted, a panel falls back to the page's first <oblyx-tab-list>, the zero-config path for the common case of one tab group per page. Every example on this page sets list explicitly: this docs site's own <Example> component renders its HTML/Kotlin source toggle using this same tab family, so a real page here always has more than one <oblyx-tab-list> on it, and the omitted-list fallback would resolve to the wrong one if we relied on it in a live demo.

Sizes

Tab sizes

One Two One Two One Two
HTMLKotlin
<oblyx-tab-list id="size-tabs-sm" value="one" size="sm">
  <oblyx-tab value="one">One</oblyx-tab>
  <oblyx-tab value="two">Two</oblyx-tab>
</oblyx-tab-list>
<oblyx-tab-list id="size-tabs-md" value="one" size="md">
  <oblyx-tab value="one">One</oblyx-tab>
  <oblyx-tab value="two">Two</oblyx-tab>
</oblyx-tab-list>
<oblyx-tab-list id="size-tabs-lg" value="one" size="lg">
  <oblyx-tab value="one">One</oblyx-tab>
  <oblyx-tab value="two">Two</oblyx-tab>
</oblyx-tab-list>
oblyxTabList(value = "one", size = OblyxTabListSize.SM) {
  oblyxTab(value = "one") { +"One" }
  oblyxTab(value = "two") { +"Two" }
}
oblyxTabList(value = "one", size = OblyxTabListSize.MD) {
  oblyxTab(value = "one") { +"One" }
  oblyxTab(value = "two") { +"Two" }
}
oblyxTabList(value = "one", size = OblyxTabListSize.LG) {
  oblyxTab(value = "one") { +"One" }
  oblyxTab(value = "two") { +"Two" }
}

Layout

hug (the default) sizes each tab to its own content. fill stretches every tab to share the strip's width equally.

Fill layout

One Two Three
HTMLKotlin
<oblyx-tab-list id="fill-tabs" value="one" layout="fill">
  <oblyx-tab value="one">One</oblyx-tab>
  <oblyx-tab value="two">Two</oblyx-tab>
  <oblyx-tab value="three">Three</oblyx-tab>
</oblyx-tab-list>
oblyxTabList(value = "one", layout = OblyxTabListLayout.FILL) {
  oblyxTab(value = "one") { +"One" }
  oblyxTab(value = "two") { +"Two" }
  oblyxTab(value = "three") { +"Three" }
}

Divider

has-divider adds a bottom divider under the whole strip, with the selected indicator dropped onto it.

Tab list with divider

One Two
HTMLKotlin
<oblyx-tab-list id="divider-tabs" value="one" has-divider>
  <oblyx-tab value="one">One</oblyx-tab>
  <oblyx-tab value="two">Two</oblyx-tab>
</oblyx-tab-list>
oblyxTabList(value = "one", hasDivider = true) {
  oblyxTab(value = "one") { +"One" }
  oblyxTab(value = "two") { +"Two" }
}

Keyboard model

ArrowRight/ArrowDown and ArrowLeft/ArrowUp move focus one tab at a time and wrap at the ends; Home and End jump to the first and last tab. Only the selected tab is a Tab stop (roving tabindex); arrow keys move focus without a separate Tab press. Selection is automatic: moving focus with an arrow key selects that tab and shows its panel in the same keystroke, rather than requiring a follow-up Enter or Space. The panels here are cheap, already-rendered content with nothing to lazily load, so there is no cost to switching immediately.

Reference

<oblyx-tab-list>

AttributeTypeDefaultDescription
valuestring | undefinedThe selected tab's value, the single source of truth for selection. Reflected so oblyx-tab-list[value="…"] is a CSS hook and so an author can pre-select a tab with a plain attribute. Starts undefined (no tab selected) until a tab-select event or a keyboard activation sets it.
sizesmmdlgmdElement height for every tab in this strip. Pure CSS.
layouthugfillhug'hug' sizes each tab to its own content; 'fill' stretches all tabs to share the strip's width equally. Pure CSS.
has-dividerbooleanfalseBottom divider under the whole strip, with the selected indicator dropped onto it. Pure CSS.

<oblyx-tab>

AttributeTypeDefaultDescription
valuestring | undefinedMatched against the tab-list's value to decide selection, and used to derive this tab's id and its aria-controls target ({listId}-panel-{value}). Required, like a native <option value>; missing it is a defect and is flagged loudly, the same convention oblyx-option.ts uses for its own required value.

Events

EventTypeDescription
tab-selectCustomEvent

<oblyx-tab-panel>

AttributeTypeDefaultDescription
valuestring | undefinedMatched against the resolved tab-list's value. Required, same convention as OblyxTab.value.
liststring | undefinedId of the <oblyx-tab-list> this panel belongs to. Optional; when unset, resolves to the single tab-list on the page.