Components › Navigation › Tabs › Record tabs

Record tabs

canon

Record tab row: tab strip plus „+ N další“ overflow and a personal layout; an empty tab drops out, a loading one does not.

React implementation lives in the app (record/RecordTabsRow.tsx + record-tabs.ts); it uses TabStrip internally and adds the overflow trigger and the layout menu. 14 Oct 2026 (owner "24g scvaleno", proto/zalozky-jeden-ovladac@489bb3bd6, acrm !5043): ONE icon button „Záložky" with a count badge of hidden tabs replaces „+ N další" and ⚙; its menu lists all tabs — name = open, switch = show/hide, grip/Alt+↑↓ = order; phone = bottom sheet with „Hotovo". Badge --accent-press + white, 5.73:1. Dev check 14 Oct 1440 + 390 (company Druid): badge 8, 15 switches, sheet ok.

Used in 4 files · 4 areas · 4× — components/company, pages/CompanyRecordPage, pages/ObchodDetailPage, pages/PersonRecordPage

Keyboard

  • The strip behaves exactly as Tab strip does: each tab is a <button role="tab">, arrow keys and Home/End move focus within one tab stop, Enter and Space switch.
  • The overflow trigger is a button that opens a canonical popover: Enter opens, Escape closes.
  • The gear is an icon button with an accessible name. Reordering: Alt+↑/↓ on a focused row moves it by one place and saves; focus stays on the moved row and a polite live region announces "<label>: position N of M". At an edge nothing is saved, the position is only announced. Dragging does the same thing with a pointer (NAV-3, 11 Sep 2026).

ARIA

  • The row itself is a plain container; the semantics come from TabStrip (role="tablist" / role="tab" / aria-selected).
  • No aria-controls here: the strip lives in RecordTabsRow and the panels in the record page, so the strip has no panel id to point at.
  • The overflow trigger is announced by its own text („+ 3 další“), so the number of hidden tabs is available without opening it.
  • Counts are read as part of the tab's name; a loading count is simply absent rather than announced as zero.
  • The gear's menu is a list of toggles; the state of each is carried by the toggle, not by the row's appearance.

Focus

  • Foundation ring from ds.css on every control in the row (tabs, overflow trigger, gear).
  • Picking a tab from the overflow closes the menu and switches the tab; focus returns to the trigger, not to the newly active tab.
  • The active tab is forced into the visible part of the strip, so focus never lands on a tab hidden behind the fade.

Contrast

Computed from packages/ui/src/tokens/tokens.css:

  • Tabs: as in Tab strip — active tab ink plus the accent underline (--accent = 4.44:1 light, 3.83:1 dark), inactive muted.
  • Overflow trigger: quiet link-like button in muted ink; it is text, so it inherits the same limit as other muted text (2.85:1 in light theme).
  • Gear: icon button in --fg-muted — below the 3:1 non-text minimum in light theme, with hover raising it.
  • Row hairline --border: below the 3:1 boundary minimum, as every hairline in the system.

Known limits

  • No aria-controls wiring to the panel (it lives outside this component).
  • The overflow trigger and the gear are muted (2.85:1 in light theme).
  • Hiding a tab is still silent; reordering is announced.

Source: docs/tabs/record-tabs.a11y.md · GitLab