Component
Tabs
Switch between views of the same thing — chart, technicals, option chain — without leaving the page. Follows the ARIA Authoring Practices tabs pattern.
- 2.1.1 Keyboard
- 2.4.3 Focus order
- 2.4.7 Focus visible
- 1.3.1 Info and relationships
- 1.4.1 Use of colour
- 4.1.2 Name, role, value
Examples
Portfolio value, today's change and buying power.
3 open positions. Unrealised P&L +₹4,210 (up).
No open orders.
Statements are generated monthly.
<tai-tabs label="Account views" value="positions" class="stretch" id="tabs-auto">
<tai-tab value="overview">Overview</tai-tab>
<tai-tab value="positions">Positions</tai-tab>
<tai-tab value="orders">Orders</tai-tab>
<tai-tab value="statements" disabled>Statements</tai-tab>
<tai-tab-panel value="overview"><p>Portfolio value, today's change and buying power.</p></tai-tab-panel>
<tai-tab-panel value="positions"><p>3 open positions. Unrealised P&L <strong class="up">+₹4,210</strong> (up).</p></tai-tab-panel>
<tai-tab-panel value="orders"><p>No open orders.</p></tai-tab-panel>
<tai-tab-panel value="statements"><p>Statements are generated monthly.</p></tai-tab-panel>
</tai-tabs>
<div class="log" role="log" aria-label="Tab events" id="log-auto"></div>Intraday 5-minute candles.
Hourly candles for the week.
Daily candles for the month.
Weekly candles for the year.
<tai-tabs label="Chart range" value="1d" activation="manual" variant="underline" class="stretch">
<tai-tab value="1d">1 day</tai-tab>
<tai-tab value="1w">1 week</tai-tab>
<tai-tab value="1m">1 month</tai-tab>
<tai-tab value="1y">1 year</tai-tab>
<tai-tab-panel value="1d"><p>Intraday 5-minute candles.</p></tai-tab-panel>
<tai-tab-panel value="1w"><p>Hourly candles for the week.</p></tai-tab-panel>
<tai-tab-panel value="1m"><p>Daily candles for the month.</p></tai-tab-panel>
<tai-tab-panel value="1y"><p>Weekly candles for the year.</p></tai-tab-panel>
</tai-tabs>Chart view.
<tai-tabs label="Market panel" value="chart" id="tabs-ext">
<tai-tab value="chart" controls="market-panel">Chart</tai-tab>
<tai-tab value="technicals" controls="market-panel">Technicals</tai-tab>
<tai-tab value="chain" controls="market-panel">Option chain</tai-tab>
</tai-tabs>
<tai-tab-panel id="market-panel" class="stretch"><p id="market-panel-text">Chart view.</p></tai-tab-panel>When to use which activation
| Mode | Behaviour | Use when |
|---|---|---|
activation="auto" (default) | Arrow keys move focus and show the panel. | Panels are already loaded or quick to show. |
activation="manual" | Arrow keys only move focus; Enter/Space shows the panel. | Showing a panel is slow or costly (fetches data, re-renders a chart). Prevents a request per keypress while the user is just passing through. |
API
| Name | Kind | Description |
|---|---|---|
value | attribute / property | Selected tab's value. Reflects. Setting it doesn't fire an event. |
label | attribute | Accessible name of the tab list. Required (or aria-labelledby on the host). |
activation | attribute | auto (default) or manual. |
orientation | attribute | horizontal (default) or vertical; arrow keys follow it. |
variant | attribute | pill (default) or underline. |
tabs | property | The <tai-tab> children. |
refresh() | method | Re-links tabs and panels. Called automatically when children change. |
tai-change | event | The user picked a tab. detail: { value, previousValue }. |
tablist, panels | parts | The role="tablist" wrapper and the panel wrapper. |
--tai-tabs-gap | custom property | Space between tabs and panels. |
| Element | Attribute | Description |
|---|---|---|
tai-tab | value | Identifies the tab. Defaults to its text. |
tai-tab | controls | id of a <tai-tab-panel> elsewhere on the page. |
tai-tab | disabled | Skipped by arrow keys; exposed as aria-disabled. |
tai-tab-panel | value | Matches its tab when the panel is inside <tai-tabs>. |
Keyboard
| Key | Action |
|---|---|
| Tab | Into the tab list lands on the selected tab; the next Tab goes to the panel. |
| → / ← | Next / previous tab, wrapping, skipping disabled tabs (↓ / ↑ when vertical). |
| Home / End | First / last tab. |
| Enter / Space | Selects the focused tab (needed in manual mode). |
Accessibility notes
They can look identical. Use tabs when each choice reveals a different panel of content. Use a segmented control (radio group) when the choice is a value — an index, a timeframe filter applied to the same view. The audit found the app using one look for both, with neither behaving correctly.
- One Tab stop for the whole list (roving
tabindex): keyboard users don't tab through every tab to reach the content. - ARIA lives on the light-DOM elements (
role="tab"on each<tai-tab>), soaria-controlsandaria-labelledbywork across the page — the tab list can sit in a toolbar while the panel is rendered by the app somewhere else. Thetablistrole is on a shadow wrapper around the tabs only, so panels never end up inside it. - Selection isn't colour alone: the selected tab is raised with an outline (or underlined), and exposed as
aria-selected="true". - Panels are focusable (
tabindex="0") as the APG recommends, so panels without links or buttons are still reachable.
Screen reader behaviour
Automated (Chrome accessibility tree): tablist with its label, tabs with selected state and position, panel labelled by the selected tab. Manual NVDA and VoiceOver passes are the next step.
Usage guidance
Do
- Keep tab labels short and parallel (“Chart”, “Technicals”).
- Use manual activation when a panel triggers a network request.
Don't
- Use tabs as page navigation — use links.
- Use tabs to pick a value (use a segmented control).
- Hide essential steps of a process in tabs.
Using it in React
import '@tradeaialgo/tai-ui'
function MarketPanel() {
const [tab, setTab] = useState('chart')
return (
<>
<tai-tabs label="Market panel" value={tab} ontai-change={e => setTab(e.detail.value)}>
<tai-tab value="chart" controls="market-panel">Chart</tai-tab>
<tai-tab value="technicals" controls="market-panel">Technicals</tai-tab>
</tai-tabs>
<tai-tab-panel id="market-panel">{tab === 'chart' ? <Chart /> : <Technicals />}</tai-tab-panel>
</>
)
}