Pular para o conteúdo

Tabs

components specs/components/tabs.kmd

Horizontal navigation within a single context — primary tabs (top of content) and secondary tabs (filter within tab). Material parity (`/components/tabs`). Includes scrollable tabs, swipe gesture, and accessibility contract.

Quando esta spec se aplica

Triggers primários

Todos os triggers

Corpo da especificação

Spec — Tabs

Facet Visual do Koder Design. Material parity: https://m3.material.io/components/tabs.

2 tab levels

LevelPositionUse
PrimaryTop of content area, beneath app barMain view switcher (Profile / Activity / Settings)
SecondaryWithin a primary tab's contentFilter within view (All / Mine / Shared)

Maximum 2 levels — never nest a 3rd. If needed, use sub-navigation (drawer, menu) at the deeper level.

Anatomy (primary tab row)

┌────────────────────────────────────────────┐
│   Profile     Activity    Settings         │   ← labels
│   ━━━━━━━                                  │   ← indicator (active)
└────────────────────────────────────────────┘
  • Container: full width, surface bg
  • Label: title-small (14/20, weight 600)
  • Indicator: 2 px line below active tab, accent color
  • Padding per tab: 16 px horizontal, 12 px vertical
  • Height: 48 px

R1 — Tab content options

ModeContent
Label onlyJust text
Icon + Label18 px icon above OR before label
Icon onlySingle 24 px icon (with aria-label)
Label + count"Inbox (12)" — count as badge or inline

Don't mix modes within a single tab row. All tabs in a row use the same mode.

R2 — States

StateLabel colorIndicator
Inactive (rest)text-muted
Inactive + hovertext
Inactive + focusedtext + focus ring
Active (current)accentaccent line (2 px)
Active + focusedaccent + focus ringaccent line
Disabled38% opacity

R3 — Indicator animation

When user clicks a different tab:

  • Indicator slides from old position to new (motion-medium, ~250ms)
  • Color of active label transitions from text-mutedaccent
  • Content area cross-fades to new content (motion-fast)
  • Reduced motion: indicator snaps; no fade

R4 — Fixed vs scrollable tabs

ModeWhenBehavior
FixedTotal tabs fit within container widthEqual-width tabs OR centered with auto sizing
ScrollableTabs overflow containerHorizontal scroll, no fixed width, indicator scrolls with tabs

Switch automatically per layout: at Compact class scroll if more than 4 tabs; at Expanded class fixed up to 6 tabs.

R5 — Swipe gesture

On touch surfaces:

  • Swipe left/right within content area switches to adjacent tab
  • Swipe matches indicator motion (1:1 with finger)
  • Release with > 50% threshold: switches; < 50%: snaps back
  • Indicator animates smoothly with swipe

Disabled when content has its own horizontal scroll (e.g., carousel).

R6 — Tab content area

  • Content area renders below tab row
  • Switching tabs: cross-fade (motion-fast) OR slide-in (motion-medium) — pick one style per app; don't mix
  • Preserve scroll position per tab (going back to "Profile" tab remembers its scroll)
  • Lazy-render content on first visit; keep mounted after

R7 — Secondary tabs

Look slightly different from primary to indicate hierarchy:

AspectPrimarySecondary
ContainerSame as toolbarSame as surrounding content
Indicator2 px solid below2 px or chip-style border
Padding16 px horizontal12 px horizontal
Label weight600500

Secondary tabs render WITHIN a primary tab's content area, not in the app bar.

R8 — Accessibility

  • role="tablist" on container
  • role="tab" on each tab; aria-selected="true" on active
  • aria-controls pointing to the panel id
  • Panel: role="tabpanel" + aria-labelledby pointing to tab id
  • Keyboard:
    • Arrow Left/Right cycles tabs (wrap around at ends)
    • Home/End jumps to first/last
    • Tab moves OUT of tab row into the panel
  • Screen reader announces: "Tab, Activity, 2 of 3, selected"

R9 — Per-preset variation

PresetIndicator
material32 px solid line at bottom
material23 px solid line at bottom
ios_cupertinoActive tab has accent-tint bg (no line)
gnomeActive tab background tint + 1 px line
windows_11Mica backdrop on row, accent line
brutalist4 px thick line + sharp corners
terminal_classicASCII underline [==Active==]

R10 — Forbidden patterns

  • ❌ More than 2 levels of tabs (use drawer/menu for deeper nav)
  • ❌ Tab labels longer than 20 chars (truncate or use shorter)
  • ❌ Hiding inactive tabs (defeats the "all options visible" purpose)
  • ❌ Confirmation dialog on tab switch (defeats quick navigation)
  • ❌ Tabs that navigate to different URLs (use links, not tabs — tabs are within ONE context)
  • interaction/states.kmd — focus/hover visuals
  • themes/color-roles.kmd — accent indicator
  • themes/motion.kmd — indicator slide animation
  • foundations/elements.kmd — Control family

Referências