Page and layout

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.tap
  • radius.pill
  • color.text.muted
  • type.size.caption
  • type.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>