Tabs
Links, so they work without JavaScript. For settings and explainers, never to hide content.
openvibe-shared/kitJSON
Build it
kit.tabs({ base: '/kit/tabs', items: [{ key: 'look', label: 'Look' }, { key: 'sound', label: 'Sound', count: 2 }, { key: 'privacy', label: 'Privacy' }], active: 'look' })Props
base- string?
items- list?
label- string?
param- string?
active- string?
Anatomy
- pillthe open one on color.bg.hover with a line, color.text.primary; minHeight size.tap; radius radius.pill; color color.text.muted
- countsize type.size.caption; weight type.weight.heavy
Behaviour and access
- Keyboard
- Standard focus order
- Outside tap
- Leaves it open
- Scroll
- The page still scrolls
- Reduced motion
- Remove movement; keep the state change.
- Name
- its label (Sections)
- Target
- 44 px on touch
- Focus
- Tab between links; Enter opens
States
- default
- current
- focused
Tokens
size.tapradius.pillcolor.text.mutedtype.size.captiontype.weight.heavy
Android · Jetpack Compose
ScrollableTabRow
@Composable fun OvTabs(tabs: List<String>, selected: Int, onSelect: (Int) -> Unit) { ScrollableTabRow(selectedTabIndex = selected, edgePadding = OvScale.SpaceLg) { tabs.forEachIndexed { i, t -> Tab(selected = i == selected, onClick = { onSelect(i) }, modifier = Modifier.heightIn(min = OvScale.SizeTap), text = { Text(t) }) } } }
iOS · SwiftUI
struct OvTabs: View { let tabs: [String] @Binding var selected: Int var body: some View { Picker("Sections", selection: $selected) { ForEach(tabs.indices, id: \.self) { Text(tabs[$0]).tag($0) } } .pickerStyle(.segmented) } }
Markup
Default
<nav class="ovk-tabs" aria-label="Sections"><a href="/kit/tabs?tab=look" aria-current="page"><span>Look</span></a><a href="/kit/tabs?tab=sound"><span>Sound</span><span class="ovk-tab-n">2</span></a><a href="/kit/tabs?tab=privacy"><span>Privacy</span></a></nav>