ReviewOS

stacks/stx

Tabs cannot be controlled: no v-model or change event, and the panels must live inside it, so URL- or store-driven tabs with lazy sections cannot use it

#2058
Closed chris opened this 9 days ago ·
9 days ago

Since #1979 the slot API works: <TabPanel> children are discovered, the tab buttons render, Arrow/Home/End move between them with a roving tabindex, and the panels toggle. Measured in an app on 0.2.459.

What it cannot do is be driven from outside, which is how an app's tabs usually work.

The two shapes it does not cover

The selection belongs to the page. defaultTab sets the first tab and nothing after that. There is no value/v-model and no change event carrying the tab, so a page that keeps its tab in the URL (?tab=sales, so a reload or a shared link lands on the same tab), or switches tab from a button elsewhere ("see your sales"), cannot use it.

The panels live elsewhere. Every tab's content has to be a <TabPanel> inside <Tabs>, and all of them are rendered up front. An app whose tabs switch between whole sections of a page, each behind its own :if so a section that is not shown does not fetch its data or build its markup, cannot use the strip without moving every section inside the component and losing the laziness.

Why it matters

hq.training has seven hand-rolled tablists (a storefront, a point of sale, a plan editor's build/type switch, and others). None of them implements the keyboard behaviour role="tablist" promises, which is exactly what this component does well. Each one is URL- or store-driven with lazily rendered sections, so none can adopt it.

Suggested shape

  • v-model (via useModel, as TextInput and Switch already do) on the selected tab's id or index, emitting change.
  • A strip-only mode: tabs given as { id, label } with no panels inside, where the component renders the tablist and its keyboard behaviour and leaves the panels to the page, wiring aria-controls to ids the page supplies (panelId(tab) or a panel-id-prefix prop).

With both, an app keeps its URL, its :if sections and its data loading, and gets the WAI-ARIA tabs behaviour from one place.

Sign in to comment on this issue.