diff --git a/fern/products/docs/pages/customization/css-selectors.mdx b/fern/products/docs/pages/customization/css-selectors.mdx
index 57d20a6a4..5411f4fe8 100644
--- a/fern/products/docs/pages/customization/css-selectors.mdx
+++ b/fern/products/docs/pages/customization/css-selectors.mdx
@@ -302,6 +302,62 @@ Mobile menu toggle button.
+## Tab menu components
+
+Selectors for header [tab menus](/learn/docs/configuration/tabs#tab-menus). These classes apply only to the header menu. The sidebar selector that replaces a tab menu on mobile and with sidebar tabs uses the `.fern-variant-selector` classes.
+
+| Selector | Element |
+| --- | --- |
+| `.fern-tab-menu` | Wrapper for one menu tab. Has `data-tab-slug` (the menu tab's slug) and `data-state` (`open` or `closed`). Also has `.fern-tab-menu-click-only` when [`layout.tab-menu.interact-on-click-only`](/learn/docs/configuration/site-level-settings#layouttab-menuinteract-on-click-only) is `true`. |
+| `.fern-tab-menu-trigger` | Header tab button. Has `data-state` (`active` or `inactive`) and `aria-expanded`. |
+| `.fern-tab-menu-chevron` | Chevron on the tab button |
+| `.fern-tab-menu-panel` | Positioning and fade layer. Has `data-state`. |
+| `.fern-tab-menu-card` | Floating card. Also has `.fern-dropdown`. |
+| `.fern-tab-menu-scroll-area`, `.fern-tab-menu-scroll` | Scroll area root and its viewport |
+| `.fern-tab-menu-columns`, `.fern-tab-menu-column` | Column container and each column |
+| `.fern-tab-menu-group-header` | Group header |
+| `.fern-tab-menu-header-spacer` | Spacer aligning columns without a group header |
+| `.fern-tab-menu-item` | Tab entry. Has `data-state` (`checked` or `unchecked`). |
+| `.fern-tab-menu-link` | Link entry |
+| `.fern-tab-menu-item-text` | Wrapper for an entry's title and subtitle |
+| `.fern-tab-menu-item-title`, `.fern-tab-menu-item-subtitle` | Entry title and subtitle |
+| `.fern-tab-menu-item-check` | Checkmark on the current entry |
+
+The menu's default styles read CSS custom properties, so setting a property on `:root` or a `.fern-tab-menu` wrapper restyles the menu without overriding its rules. The default styles sit in `@layer components`, so unlayered custom CSS overrides them regardless of specificity.
+
+| Property | Default |
+| --- | --- |
+| `--fern-tab-menu-offset` | `0.5rem` |
+| `--fern-tab-menu-padding` | `0.5rem` |
+| `--fern-tab-menu-radius` | `1rem` |
+| `--fern-tab-menu-shadow` | `0 16px 40px -12px rgb(0 0 0 / 18%), 0 2px 6px rgb(0 0 0 / 4%)` |
+| `--fern-tab-menu-max-height` | `min(75vh, 40rem)` |
+| `--fern-tab-menu-scrollbar-inset` | `0.75rem 0.375rem` |
+| `--fern-tab-menu-column-min-width` | `12rem` |
+| `--fern-tab-menu-column-max-width` | `17rem` |
+| `--fern-tab-menu-column-gap` | `0.5rem` |
+| `--fern-tab-menu-item-gap` | `0.25rem` |
+| `--fern-tab-menu-item-padding` | `0.5rem 0.75rem` |
+| `--fern-tab-menu-item-radius` | `0.5rem` |
+| `--fern-tab-menu-item-hover-background` | `var(--accent-a3)` |
+| `--fern-tab-menu-item-hover-color` | `var(--accent-a11)` |
+| `--fern-tab-menu-item-selected-background` | `var(--accent-a3)` |
+| `--fern-tab-menu-item-selected-color` | `var(--accent-a12)` |
+| `--fern-tab-menu-group-header-color` | `var(--grayscale-a10)` |
+| `--fern-tab-menu-item-title-font-size` | `0.875rem` |
+| `--fern-tab-menu-item-subtitle-font-size` | `0.75rem` |
+
+```css Example: Restyle tab menus
+:root {
+ --fern-tab-menu-radius: 0.5rem;
+ --fern-tab-menu-item-selected-background: var(--accent-a4);
+}
+
+.fern-tab-menu[data-tab-slug="products"] .fern-tab-menu-item-title {
+ font-weight: 600;
+}
+```
+
## Sidebar components
Selectors for sidebar navigation and tabs.
@@ -3164,6 +3220,24 @@ The sections of this page document the most commonly customized selectors in det
.fern-step | Class |
.fern-steps | Class |
.fern-stream | Class |
+ .fern-tab-menu | Class |
+ .fern-tab-menu-card | Class |
+ .fern-tab-menu-chevron | Class |
+ .fern-tab-menu-click-only | Class |
+ .fern-tab-menu-column | Class |
+ .fern-tab-menu-columns | Class |
+ .fern-tab-menu-group-header | Class |
+ .fern-tab-menu-header-spacer | Class |
+ .fern-tab-menu-item | Class |
+ .fern-tab-menu-item-check | Class |
+ .fern-tab-menu-item-subtitle | Class |
+ .fern-tab-menu-item-text | Class |
+ .fern-tab-menu-item-title | Class |
+ .fern-tab-menu-link | Class |
+ .fern-tab-menu-panel | Class |
+ .fern-tab-menu-scroll | Class |
+ .fern-tab-menu-scroll-area | Class |
+ .fern-tab-menu-trigger | Class |
.fern-table | Class |
.fern-table-collapse | Class |
.fern-table-pagination | Class |
diff --git a/fern/products/docs/pages/navigation/site-level-settings.mdx b/fern/products/docs/pages/navigation/site-level-settings.mdx
index 6a0339955..3bc96b243 100644
--- a/fern/products/docs/pages/navigation/site-level-settings.mdx
+++ b/fern/products/docs/pages/navigation/site-level-settings.mdx
@@ -605,6 +605,9 @@ layout:
sidebar-width: 336px
searchbar-placement: header
tabs-placement: header
+ tab-menu:
+ default-column-height: 4
+ interact-on-click-only: true
switcher-placement: sidebar
content-alignment: left
hide-nav-links: true
@@ -648,6 +651,14 @@ layout:
This setting is ignored when `disable-header` is set to true.
+
+ Maximum number of entries per column in every header [tab menu](/learn/docs/configuration/tabs#tab-menus) that doesn't set its own `tab-menu-column-height`. `no-limit` keeps a single column. When neither is set, each menu group gets one column with no height limit.
+
+
+
+ When `true`, header [tab menus](/learn/docs/configuration/tabs#tab-menus) open and close only when the tab is selected, not on hover, and have no open animation. By default, they open on hover and close when the pointer leaves the tab and menu.
+
+
Set the placement of the product and version switchers. Can be one of `header` or `sidebar`.
diff --git a/fern/products/docs/pages/navigation/tabs.mdx b/fern/products/docs/pages/navigation/tabs.mdx
index 36c0c4f8c..3c220901e 100644
--- a/fern/products/docs/pages/navigation/tabs.mdx
+++ b/fern/products/docs/pages/navigation/tabs.mdx
@@ -8,6 +8,8 @@ max-toc-depth: 3
Tabs split a product or version into parallel bodies of content, each with its own sidebar. Tab variants give a single tab more than one version of its content, such as REST versus GraphQL or beginner versus advanced.
+With tabs in the header, a [tab menu](#tab-menus) groups several tabs under one header tab, such as a product switcher.
+
Two tabs make sense when the content is unrelated, like guides and an API Reference. Variants of one tab make sense when it covers the same ground for a different reader.
## Tabs
@@ -109,6 +111,14 @@ theme:
External URL. When set, clicking the tab redirects to this URL. Tabs with `href` must not include `layout` or `variants`.
+
+ Turns the tab into a [tab menu](#tab-menus) of other tabs, groups, and links. A tab with a `tab-menu` has no `layout` or `variants` of its own.
+
+
+
+ Maximum number of entries per column in this tab's menu. `no-limit` keeps a single column. Overrides [`layout.tab-menu.default-column-height`](/learn/docs/configuration/site-level-settings#layouttab-menudefault-column-height). Only applies to tabs with a `tab-menu`.
+
+
Where the link opens. One of `_blank`, `_self`, `_parent`, or `_top`.
@@ -236,6 +246,37 @@ navigation:
+### Grouped variants
+
+A `variants` list can also hold `group` entries and `link` entries. A `group` has a header and an `items` list of variants and links. A `link` adds an external URL to the selector. When the list has groups or links, the sidebar selector shows every entry in one stacked list under its group header.
+
+```yaml title="docs.yml"
+navigation:
+ - tab: sdks
+ variants:
+ - group: Server SDKs
+ items:
+ - title: Python
+ default: true
+ layout:
+ - page: Quickstart
+ path: ./pages/python/quickstart.mdx
+ - title: TypeScript
+ layout:
+ - page: Quickstart
+ path: ./pages/typescript/quickstart.mdx
+ - group: Mobile SDKs
+ items:
+ - title: Swift
+ layout:
+ - page: Quickstart
+ path: ./pages/swift/quickstart.mdx
+ - link: Community SDKs
+ href: https://github.com/example/community-sdks
+```
+
+Link entries take `link` (display text), `href`, and optional `icon` and `target`.
+
### Variant properties
@@ -281,3 +322,123 @@ navigation:
Conditional display configuration
+
+## Tab menus
+
+A tab menu turns a header tab into a dropdown that lists other tabs, grouped into columns, along with external links. Use it to build a product switcher in the header instead of a long row of tabs. Tab menus require [tabs in the header](#tabs-placement-and-styling). With tabs in the sidebar, the menu's tabs show in a selector at the top of the sidebar instead.
+
+To configure a tab menu:
+
+- Declare the menu tab under `tabs` with a `tab-menu` list. Each entry is a tab, a `group` of tabs and links, or a link.
+- Declare each tab in the menu only inside its menu entry, not under `tabs`.
+- In `navigation`, add `- tab:` for the menu tab with no `layout` or `variants`. Its position sets where the menu sits in the header.
+- In `navigation`, give each tab in the menu its own `- tab:` entry with a `layout`, or with `variants` to show a selector at the top of that tab's sidebar.
+
+```yaml title="docs.yml"
+layout:
+ tabs-placement: header
+
+tabs:
+ products:
+ display-name: Products
+ tab-menu-column-height: 2
+ tab-menu:
+ - group: Platform
+ tabs:
+ - tab: agents
+ display-name: Agents
+ subtitle: Build AI agents
+ icon: fa-solid fa-robot
+ - tab: studio
+ display-name: Studio
+ - link: Status
+ href: https://status.example.com
+ guides:
+ display-name: Guides
+
+navigation:
+ - tab: products # Menu tab: no layout or variants
+ - tab: agents
+ variants: # Selector at the top of the Agents sidebar
+ - title: Python
+ default: true
+ layout:
+ - page: Quickstart
+ path: ./pages/agents/python.mdx
+ - title: TypeScript
+ layout:
+ - page: Quickstart
+ path: ./pages/agents/typescript.mdx
+ - tab: studio
+ layout:
+ - page: Overview
+ path: ./pages/studio/overview.mdx
+ - tab: guides
+ layout:
+ - page: Getting started
+ path: ./pages/guides/getting-started.mdx
+```
+
+URLs for tabs in a menu nest under the menu tab, for example `/products/agents/python/quickstart`. Selecting a tab with variants opens its `default: true` variant, or the first variant.
+
+Each `group` starts a new column, and ungrouped entries share one column. A column continues into a new one after the number of entries set by the tab's [`tab-menu-column-height`](#tab-menu-column-height), or the site-wide [`layout.tab-menu.default-column-height`](/learn/docs/configuration/site-level-settings#layouttab-menudefault-column-height). Menus open on hover by default. Set [`layout.tab-menu.interact-on-click-only`](/learn/docs/configuration/site-level-settings#layouttab-menuinteract-on-click-only) to `true` to open and close them only when the tab is selected, with no animation. To restyle menus, use the [tab menu CSS selectors](/learn/docs/customization/css-selectors-reference#tab-menu-components).
+
+### Tab menu entry properties
+
+Tabs in a `tab-menu`, directly or inside a `group`, accept these properties. The `tab` value is the ID that the tab's `- tab:` entry in `navigation` uses.
+
+
+ ID of the tab. Must match a `- tab:` entry in `navigation`.
+
+
+
+ Name shown in the menu
+
+
+
+ Text displayed below the name
+
+
+
+
+
+
+
+ Custom URL slug for the tab
+
+
+
+ Exclude the tab slug from URLs
+
+
+
+ Hide the tab from the menu
+
+
+
+ When true, this tab displays by default for the menu tab. If not specified, the first tab is used.
+
+
+
+ Role-based access control for the tab
+
+
+
+ Conditional display configuration
+
+
+A `group` entry takes `group` (the column header) and a `tabs` list of tab and link entries. A link entry takes `link` (display text), `href`, and optional `icon` and `target`.
+
+
+### Tab menu errors
+
+`fern check` reports these errors for tab menus:
+
+- A tab in a `tab-menu` has no `- tab:` entry in `navigation`, or its entry has neither `layout` nor `variants`.
+- A tab is listed in more than one `tab-menu`, or is both in a `tab-menu` and under `tabs`.
+- The menu tab's `navigation` entry has its own `layout` or `variants`. Put pages under each menu entry's own `- tab:` entry.
+- A menu entry's tab is in `navigation`, but its menu tab isn't. Add `- tab:
diff --git a/fern/products/home/pages/fern-instructions/docs/configure/navigation.mdx b/fern/products/home/pages/fern-instructions/docs/configure/navigation.mdx
index 2037d5289..a186b3cdd 100644
--- a/fern/products/home/pages/fern-instructions/docs/configure/navigation.mdx
+++ b/fern/products/home/pages/fern-instructions/docs/configure/navigation.mdx
@@ -37,6 +37,8 @@ Use this to change the sidebar or any page URL.
| `availability` | Badge such as `beta` or `deprecated` |
| `slug`, `skip-slug` | Control the URL segment |
| `tabs` + `tab:` entries | Top-level tabs, each with its own navigation |
+| `tab-menu` on a tab | Header dropdown grouping other tabs and links into columns. Requires `layout.tabs-placement: header`. Each tab in the menu keeps its own `- tab:` entry in `navigation`; the menu tab's entry has no `layout`. |
+| `group` entries in `variants` | Variant selector split under group headers, with optional `link` entries |
| `versions` | Versioned docs, each version with its own `.yml` navigation |
| `products` | Product switcher. Each product has its own `.yml`, and the top-level `docs.yml` then has no `navigation` of its own. Requires a Team or Enterprise plan. |