Tabbed interface with manual activation and roving tabindex. Supports horizontal and vertical orientation.
Installation
import "monochrome" // Core (auto-activates)
import { Tabs } from "monochrome/react" // React
import { Tabs } from "monochrome/vue" // Vue
Usage
import { Tabs } from "monochrome/react"
<Tabs.Root
defaultValue="tab1"
orientation="horizontal"
>
<Tabs.List>
<Tabs.Tab value="tab1">Tab 1</Tabs.Tab>
<Tabs.Tab value="tab2" disabled>
Tab 2
</Tabs.Tab>
<Tabs.Tab value="tab3">Tab 3</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="tab1">Content 1</Tabs.Panel>
<Tabs.Panel value="tab2">Content 2</Tabs.Panel>
<Tabs.Panel value="tab3">Content 3</Tabs.Panel>
</Tabs.Root>
<script setup lang="ts">
import { Tabs } from "monochrome/vue"
</script>
<template>
<Tabs.Root
default-value="tab1"
orientation="horizontal"
>
<Tabs.List>
<Tabs.Tab value="tab1">Tab 1</Tabs.Tab>
<Tabs.Tab value="tab2" :disabled="true">
Tab 2
</Tabs.Tab>
<Tabs.Tab value="tab3">Tab 3</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="tab1">Content 1</Tabs.Panel>
<Tabs.Panel value="tab2">Content 2</Tabs.Panel>
<Tabs.Panel value="tab3">Content 3</Tabs.Panel>
</Tabs.Root>
</template>
In Vue templates, defaultValue is written as default-value (standard Vue kebab-case mapping).
API Reference
Root
The root container for the tabs component.
| Prop | Type | Default | Description |
|---|
defaultValue | string | — | Initially selected tab |
orientation | "horizontal" | "vertical" | "horizontal" | Arrow key direction |
List
The container for tab buttons.
No props.
Tab
A single tab button.
| Prop | Type | Default | Description |
|---|
value | string | — | Unique tab identifier |
disabled | boolean | false | Cannot activate, skipped by keyboard |
All Tab buttons must be direct children of the List — the core iterates via parentElement.firstElementChild.
Panel
The content region associated with a tab.
| Prop | Type | Default | Description |
|---|
value | string | — | Must match a Tab’s value |
focusable | boolean | true | Set false when panel has its own focusable elements |
DOM Structure
Root [data-orientation] → List [role=tablist] → Tab (button) [role=tab]
→ Panel [role=tabpanel]
Keyboard Navigation
Horizontal Orientation
| Key | Action |
|---|
| ArrowRight | Move focus to next tab |
| ArrowLeft | Move focus to previous tab |
| Home | Move focus to first tab |
| End | Move focus to last tab |
| Enter or Space | Activate focused tab |
Vertical Orientation
| Key | Action |
|---|
| ArrowDown | Move focus to next tab |
| ArrowUp | Move focus to previous tab |
| Home | Move focus to first tab |
| End | Move focus to last tab |
| Enter or Space | Activate focused tab |
Uses manual activation — arrow keys move focus but don’t activate the tab. Press Enter/Space to activate.
Accessibility
- Uses
role="tab" and role="tabpanel" for proper semantics
- Uses
aria-selected to indicate active tab
- Uses
aria-controls to link tab to panel
- Uses
aria-labelledby to associate panel with tab
- Uses
aria-disabled="true" for disabled tabs (not HTML disabled attribute)
- Uses roving
tabindex — only the selected tab is focusable (tabindex="0")
- Uses
hidden="until-found" to preserve browser find-in-page (Ctrl+F / Cmd+F)
- Triggers
beforematch event to auto-open when find-in-page reveals hidden content
Monochrome is headless — no CSS shipped. You provide all styles.
Browser Requirements
Requires Baseline 2024 features:
hidden="until-found" — preserves Ctrl+F / Cmd+F for hidden content
beforematch event — auto-opens components when find-in-page reveals hidden content