---
title: "Shared Layout Architecture"
description: "Fumadocs provides a modular layout architecture built around customizable slot components, context providers, and responsive structural containers across package implementations like Radix UI Primi..."
last_updated: "2026-10-12T07:53:59.981993+00:00"
canonical_url: "https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/ui-layouts/shared-layout-architecture"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/radix-ui/src/layouts/notebook/page/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/page/index.tsx)
- [packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx)
- [packages/base-ui/src/layouts/notebook/slots/sidebar.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/slots/sidebar.tsx)
- [packages/base-ui/src/layouts/notebook/page/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/page/index.tsx)
- [packages/base-ui/src/layouts/flux/page/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/page/index.tsx)
- [packages/radix-ui/src/layouts/flux/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/index.tsx)
- [packages/base-ui/src/layouts/flux/slots/sidebar.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/slots/sidebar.tsx)
- [packages/base-ui/src/layouts/flux/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/index.tsx)
- [packages/radix-ui/src/layouts/flux/page/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/page/index.tsx)
- [packages/radix-ui/src/layouts/flux/slots/sidebar.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/slots/sidebar.tsx)
- [packages/openapi/src/ui/operation/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/openapi/src/ui/operation/index.tsx)
- [packages/radix-ui/src/layouts/notebook/client.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/client.tsx)
- [packages/radix-ui/src/layouts/notebook/slots/header.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/header.tsx)
- [packages/base-ui/src/layouts/notebook/slots/header.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/slots/header.tsx)
- [packages/base-ui/src/layouts/notebook/client.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/client.tsx)
- [packages/base-ui/src/layouts/flux/page/slots/container.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/page/slots/container.tsx)
- [packages/base-ui/src/layouts/home/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/home/index.tsx)
- [packages/base-ui/src/layouts/flux/page/slots/footer.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/page/slots/footer.tsx)
- [packages/base-ui/src/components/sidebar/base.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/components/sidebar/base.tsx)
- [packages/radix-ui/src/layouts/notebook/slots/container.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/container.tsx)
- [packages/radix-ui/src/layouts/home/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/home/index.tsx)
- [packages/radix-ui/src/components/sidebar/base.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/components/sidebar/base.tsx)
- [packages/radix-ui/src/layouts/notebook/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/index.tsx)
- [packages/base-ui/src/layouts/notebook/slots/container.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/slots/container.tsx)
- [packages/preview/src/pages/...slugs.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/preview/src/pages/%5B...slugs%5D.tsx)
- [packages/base-ui/src/layouts/notebook/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/index.tsx)
- [packages/base-ui/src/layouts/notebook/page/slots/container.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/page/slots/container.tsx)
- [packages/radix-ui/src/layouts/notebook/page/slots/container.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/page/slots/container.tsx)
- [packages/radix-ui/src/layouts/flux/page/slots/container.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/page/slots/container.tsx)
- [packages/cli/src/commands/customise.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/cli/src/commands/customise.ts)
</details>

## Overview

Fumadocs provides a modular layout architecture built around customizable slot components, context providers, and responsive structural containers across package implementations like [Radix UI Primitives](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/ui-layouts/radix-ui-primitives) and [Base UI Components](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/ui-layouts/base-ui-components). This architecture decomposes complex documentation interfaces—such as the notebook and [Ui Layouts Layout](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/ui-layouts/ui-layouts-layout) variants—into discrete, swappable parts including sidebars, headers, navigation panels, and page containers. By managing state centrally through React context hooks and supporting flexible slot overrides via the [Fumadocs CLI](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/developer-tooling/fumadocs-cli), developers can easily customize individual layout pieces or construct tailored documentation experiences from the ground up without modifying core logic.

Sources: [packages/radix-ui/src/layouts/notebook/page/index.tsx:77-124](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/page/index.tsx#L77-L124), [packages/radix-ui/src/layouts/flux/index.tsx:33-42](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/index.tsx#L33-L42), [packages/cli/src/commands/customise.ts:116-160](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/cli/src/commands/customise.ts#L116-L160)

## Layout Composition and Slot Contract

### Slot Interfaces and Component Bindings

Layout composition across UI implementations relies on typed slot contracts that permit developers to override structural sub-components without breaking internal context bindings. In the Flux layout, the `DocsSlots` interface extends `BaseSlots` by defining custom component types for `container`, `tabDropdown`, and a structured `sidebar` object containing `provider`, `trigger`, `root`, and `useSidebar` hooks.

```typescript
export interface DocsSlots extends BaseSlots {
  container: FC<ComponentProps<'div'>>;
  tabDropdown: FC<TabDropdownProps>;
  sidebar: {
    provider: FC<SidebarProviderProps>;
    trigger: FC<ComponentProps<'button'>>;
    root: FC<SidebarProps>;
    useSidebar: () => { collapsed: boolean; open: boolean; setOpen: (v: boolean) => void };
  };
}
```
Sources: [packages/radix-ui/src/layouts/flux/index.tsx:33-42](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/index.tsx#L33-L42)

Similarly, the Home layout defines `HomeSlots` extending `BaseSlots` with header and container slots, bound directly to React context via `createContext` and consumed through custom hooks like `useHomeLayout`.

```typescript
export interface HomeSlots extends BaseSlots {
  header: FC<ComponentProps<'header'>>;
  container: FC<ComponentProps<'main'>>;
}
```
Sources: [packages/radix-ui/src/layouts/home/index.tsx:22-25](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/home/index.tsx#L22-L25)

| Layout Variant | Primary Container Slot | Header / Navigation Slot | Sidebar Slot Structure |
| :--- | :--- | :--- | :--- |
| **Flux Layout** | `slots.container` (`Container`) | `renderNavigationPanel` / `tabDropdown` | `slots.sidebar` (`provider`, `root`, `trigger`, `useSidebar`) |
| **Home Layout** | `slots.container` (`Container`) | `slots.header` (`Header`) | Not applicable (nav enabled via `nav.enabled`) |
| **Notebook Layout** | Resolved via `LayoutBody` / `containerProps` | `tabMode` (`sidebar` or `navbar`) | Sidebar options and tab resolution |

Sources: [packages/radix-ui/src/layouts/flux/index.tsx:33-41](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/index.tsx#L33-L41), [packages/radix-ui/src/layouts/home/index.tsx:22-25](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/home/index.tsx#L22-L25), [packages/radix-ui/src/layouts/notebook/index.tsx:13-21](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/index.tsx#L13-L21)

> [!NOTE]
> Layout contexts enforce strict tree containment; attempting to consume layout hooks outside their respective provider wrappers throws an explicit runtime error instructing developers to verify component nesting.
Sources: [packages/radix-ui/src/layouts/flux/index.tsx:69-76](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/index.tsx#L69-L76), [packages/radix-ui/src/layouts/home/index.tsx:34-39](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/home/index.tsx#L34-L39)

### Tab Resolution and Layout Options

The Notebook and Flux layouts accept flexible tab configurations through the `tabs` property, which can be provided as an explicit array of `LayoutTab` objects, a `GetLayoutTabsOptions` configuration object, or set to `false` to disable tabs entirely. When passed as an object or omitted entirely, `getLayoutTabs` dynamically extracts tab structures from the page tree.

```typescript
  const resolvedTabs = useMemo(() => {
    if (Array.isArray(tabs)) {
      return tabs;
    }
    if (typeof tabs === 'object') {
      return getLayoutTabs(tree, tabs);
    }
    if (tabs !== false) {
      return getLayoutTabs(tree);
    }
    return [];
  }, [tabs, tree]);
```
Sources: [packages/radix-ui/src/layouts/notebook/index.tsx:38-49](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/index.tsx#L38-L49)

> [!WARNING]
> Defining `tabs` inside `sidebar` options is deprecated across notebook and flux layouts; configure layout-level `tabs` directly on the root layout props to prevent fallback warnings.
Sources: [packages/radix-ui/src/layouts/flux/index.tsx:56-59](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/index.tsx#L56-L59), [packages/radix-ui/src/layouts/notebook/index.tsx:23-28](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/index.tsx#L23-L28)

## Sidebar Primitive Architecture

### Provider Contexts and Mode Detection

The sidebar architecture relies on provider contexts and reactive state hooks to manage visibility across viewports. `SidebarProvider` initializes state variables for `open` and `collapsed`, while determining the active display mode via media query evaluation. 

```typescript
type Mode = 'drawer' | 'full';

interface SidebarContext {
  open: boolean;
  setOpen: React.Dispatch<React.SetStateAction<boolean>>;
  collapsed: boolean;
  setCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
  closeOnRedirect: RefObject<boolean>;
  defaultOpenLevel: number;
  prefetch?: boolean;
  mode: Mode;
}
```
Sources: [packages/base-ui/src/components/sidebar/base.tsx:32-64](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/components/sidebar/base.tsx#L32-L64), [packages/radix-ui/src/components/sidebar/base.tsx:32-64](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/components/sidebar/base.tsx#L32-L64)

The active layout mode switches between `'drawer'` and `'full'` based on a screen width breakpoint of `768px`.

| Mode Value | Viewport Condition | Behavior |
| :--- | :--- | :--- |
| `drawer` | `(width < 768px)` | Mobile overlay drawer controlled by `SidebarDrawerOverlay` and `SidebarDrawerContent` |
| `full` | `(width >= 768px)` | Persistent desktop sidebar supporting collapsing and hover peek states |

Sources: [packages/base-ui/src/components/sidebar/base.tsx:84-84](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/components/sidebar/base.tsx#L84-L84), [packages/radix-ui/src/components/sidebar/base.tsx:84-84](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/components/sidebar/base.tsx#L84-L84)

> [!IMPORTANT]
> Consuming `useSidebar` outside of a component wrapped in `SidebarProvider` throws an explicit runtime error requiring a parent layout context such as `<DocsLayout />`.
Sources: [packages/base-ui/src/components/sidebar/base.tsx:114-122](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/components/sidebar/base.tsx#L114-L122), [packages/radix-ui/src/components/sidebar/base.tsx:114-122](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/components/sidebar/base.tsx#L114-L122)

### Viewport and Scroll Management

Sidebar content is rendered within `SidebarViewport`, which nests a `ScrollArea` and `ScrollViewport` component combined with overflow containment and vertical fade gradient mask utility classes.

```typescript
export function SidebarViewport({ className, ...props }: ScrollAreaProps) {
  return (
    <ScrollArea
      className={(s) =>
        cn('min-h-0 flex-1', typeof className === 'function' ? className(s) : className)
      }
      {...props}
    >
      <ScrollViewport className="p-4 overscroll-contain mask-[linear-gradient(to_bottom,transparent,white_12px,white_calc(100%-12px),transparent)]">
        {props.children}
      </ScrollViewport>
    </ScrollArea>
  );
}
```
Sources: [packages/base-ui/src/components/sidebar/base.tsx:222-235](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/components/sidebar/base.tsx#L222-L235)

> [!TIP]
> `SidebarContent` monitors pointer entry and leave events to handle collapsible sidebar peek behavior on desktop, applying a `500ms` close delay when the mouse pointer leaves towards the page body rather than the viewport edge.
Sources: [packages/base-ui/src/components/sidebar/base.tsx:170-180](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/components/sidebar/base.tsx#L170-L180), [packages/radix-ui/src/components/sidebar/base.tsx:172-182](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/components/sidebar/base.tsx#L172-L182)

## Navigation Sidebar Slot Wiring

### Notebook Layout Sidebar Assembly

The notebook layout sidebar implementation structures its contents using base primitives, link item renderers, and page tree configurations. `SidebarProps` accepts optional page tree components, banner elements, footer nodes, and a desktop collapsing flag.
Sources: [packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx:50-60](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx#L50-L60)

```typescript
export interface SidebarProps extends ComponentProps<'aside'> {
  components?: Partial<SidebarPageTreeComponents>;
  banner?: ReactNode | FC<ComponentProps<'div'>>;
  footer?: ReactNode | FC<ComponentProps<'div'>>;
  /**
   * Support collapsing the sidebar on desktop mode
   *
   * @defaultValue true
   */
  collapsible?: boolean;
}
```
Sources: [packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx:50-60](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx#L50-L60)

The `SidebarContent` component checks `useNotebookLayout()` to determine navigation mode settings, evaluating whether `navMode` is set to `'auto'` or alternative layout parameters to calculate sticky positioning offsets against top row heights.
Sources: [packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx:78-84](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx#L78-L84)

> [!WARNING]
> `SidebarContent` inside the notebook layout applies fixed positioning calculations that depend directly on `--fd-docs-row-1` or `--fd-docs-row-2` CSS variables; altering top row heights without matching these variable definitions breaks vertical alignment.
Sources: [packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx:92-95](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx#L92-L95)

Mobile drawer toggles are governed by `SidebarDrawer`, which pairs `Base.SidebarDrawerOverlay` featuring backdrop blur effects with `Base.SidebarDrawerContent` styled as a fixed right- or left-hand panel constrained to `85%` width up to a maximum of `380px`.
Sources: [packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx:128-146](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx#L128-L146)

### Flux Layout Sidebar Integration

The `Flux` layout implements its sidebar slot by pulling menu items from `useFluxLayout()`, filtering out icon-only entries, and passing remaining items through `SidebarLinkItem` alongside page tree renderers and viewport wrappers.
Sources: [packages/radix-ui/src/layouts/flux/slots/sidebar.tsx:64-81](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/slots/sidebar.tsx#L64-L81)

```tsx
export function Sidebar({ footer, banner, components, ...rest }: SidebarProps) {
  const { menuItems } = useFluxLayout();

  return (
    <SidebarContent {...rest}>
      <div className="flex flex-col gap-3 p-4 pb-2 empty:hidden">{banner}</div>
      <Base.SidebarViewport viewport={{ className: '*:gap-0!' }}>
        {menuItems
          .filter((v) => v.type !== 'icon')
          .map((item, i, list) => (
            <SidebarLinkItem key={i} item={item} className={cn(i === list.length - 1 && 'mb-4')} />
          ))}
        <SidebarPageTree {...components} />
      </Base.SidebarViewport>
      {footer}
    </SidebarContent>
  );
}
```
Sources: [packages/radix-ui/src/layouts/flux/slots/sidebar.tsx:64-81](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/slots/sidebar.tsx#L64-L81)

Animated sidebar triggers switch between open and closed state icons using motion transitions:
Sources: [packages/radix-ui/src/layouts/flux/slots/sidebar.tsx:83-109](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/slots/sidebar.tsx#L83-L109)

| State | Icon Component | Animation Transition |
| :--- | :--- | :--- |
| Open | `XIcon` | `y: '100%'` initial, `duration: 0.2` |
| Closed | `SidebarIcon` | `y: '100%'` initial, `duration: 0.2` |

Sources: [packages/radix-ui/src/layouts/flux/slots/sidebar.tsx:83-109](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/slots/sidebar.tsx#L83-L109)

> [!TIP]
> The `Flux` sidebar modal registers a global `keydown` event listener via `useEffectEvent` that intercepts the `Escape` key when `open` is true, immediately dismissing the drawer and preventing default event propagation.
Sources: [packages/radix-ui/src/layouts/flux/slots/sidebar.tsx:116-127](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/slots/sidebar.tsx#L116-L127)

## Header and Navbar Interactions

### Header Orchestration and Layout Tabs

The `Header` component implements sticky header navigation under the grid area `#nd-subnav`, incorporating backdrop blur styling and dynamic background transparency based on `isNavTransparent` and sidebar open states. Navigation modes are evaluated through `nav.mode`, defaulting to `'auto'`, while sidebar collapse triggers adapt their visibility depending on whether collapse rules and top navigation modes are active.

```tsx
<header
  id="nd-subnav"
  data-transparent={isNavTransparent && !open}
  {...props}
  className={cn(
    'sticky [grid-area:header] flex flex-col top-(--fd-docs-row-1) z-10 backdrop-blur-sm transition-colors data-[transparent=false]:bg-fd-background/80 layout:[--fd-header-height:--spacing(14)]',
    showLayoutTabs && 'lg:layout:[--fd-header-height:--spacing(24)]',
    props.className,
  )}
>
```
Sources: [packages/radix-ui/src/layouts/notebook/slots/header.tsx:36-45](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/header.tsx#L36-L45)

Layout tabs are rendered via `LayoutHeaderTabs` when `tabMode` is set to `'navbar'` and `tabs.length` exceeds zero. Active tabs are resolved against the current route pathname using `isLayoutTabActive`, applying primary border styling to matching route entries while supporting unlisted route filtering.

| Tab Property | Type / Behavior | Purpose |
| :--- | :--- | :--- |
| `title` | `ReactNode` | Display label inside the navbar tab anchor |
| `url` | `string` | Target destination route for the layout tab |
| `unlisted` | `boolean` | Hides the tab when inactive if set to true |
| `props` | `ComponentProps<'a'>` | Additional custom attributes or className overrides |

Sources: [packages/radix-ui/src/layouts/notebook/slots/header.tsx:161-196](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/header.tsx#L161-L196)

> [!WARNING]
> When `tabMode` is configured as `'navbar'`, the header height definition automatically scales from `--spacing(14)` up to `--spacing(24)` on large viewports (`lg:layout:[--fd-header-height:--spacing(24)]`), which directly impacts sticky offset calculations for content containers and sidebars.
Sources: [packages/radix-ui/src/layouts/notebook/slots/header.tsx:40-42](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/header.tsx#L40-L42)

### Navbar Link Items and Device Pointer Controls

Navbar link items are processed by filtering out icon-only entries for desktop display while mapping icon items to ghost button variants with muted text styling. Custom items bypass standard rendering to execute their embedded children directly, whereas menu items delegate to popover dropdown subcomponents.

```tsx
<div className="flex flex-1 items-center justify-end md:gap-2">
  <div className="flex items-center gap-6 empty:hidden max-lg:hidden">
    {navItems
      .filter((item) => item.type !== 'icon')
      .map((item, i) => (
        <NavbarLinkItem key={i} item={item} />
      ))}
  </div>
  {navItems
    .filter((item) => item.type === 'icon')
    .map((item, i) => (
      <LinkItem
        key={i}
        item={item}
        className={cn(
          buttonVariants({ size: 'icon-sm', color: 'ghost' }),
          'text-fd-muted-foreground max-lg:hidden',
        )}
        aria-label={item.label}
      >
        {item.icon}
      </LinkItem>
    ))}
```
Sources: [packages/radix-ui/src/layouts/notebook/slots/header.tsx:86-108](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/header.tsx#L86-L108)

Mobile layouts hide desktop link items and search triggers in favor of compact search buttons (`slots.searchTrigger.sm`) and sidebar drawer toggles (`slots.sidebar.trigger`). On desktop viewports, language selection components (`slots.languageSelect.root`), theme switches (`slots.themeSwitch`), and collapsible sidebar triggers are aligned within an end-oriented flex container.

> [!TIP]
> Custom navigation components can completely bypass the default header layout by passing a custom React element directly to `nav.component`, triggering an immediate return statement before standard CSS classes or DOM nodes are evaluated.
Sources: [packages/radix-ui/src/layouts/notebook/slots/header.tsx:33-33](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/header.tsx#L33-L33)

## Page Content and Container Structures

### Notebook Layout Container and Grid Template

The `Container` component within the notebook layout establishes a CSS grid container (`#nd-notebook-layout`) that manages column and row dimensions for sidebars, headers, [table of contents](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/ui-layouts/table-of-contents) popovers, and main article areas. It tracks sidebar collapse state via `slots.sidebar?.useSidebar?.()` and applies a temporary transition attribute `data-column-changed={isCollapseChanged}` whenever collapse toggles occur.

```tsx
export function Container(props: ComponentProps<'div'>) {
  const {
    props: { nav },
    slots,
  } = useNotebookLayout();
  const pageCol =
    'calc(var(--fd-layout-width,97rem) - var(--fd-sidebar-col) - var(--fd-toc-width))';
  const { collapsed } = slots.sidebar?.useSidebar?.() ?? {};
  const [previousCollapsed, setPreviousCollapsed] = useState(collapsed);
  const isCollapseChanged = previousCollapsed !== collapsed;

  // will only set data attribute for an instant
  useEffect(() => {
    if (isCollapseChanged) setPreviousCollapsed(collapsed);
  }, [collapsed, isCollapseChanged]);

```
Sources: [packages/radix-ui/src/layouts/notebook/slots/container.tsx:7-22](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/container.tsx#L7-L22), [packages/base-ui/src/layouts/notebook/slots/container.tsx:7-22](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/slots/container.tsx#L7-L22)

The grid layout geometry calculates column widths using `var(--fd-layout-width, 97rem)`, subtracting sidebar and TOC widths to resolve the central page column (`pageCol`). The template columns string enforces minimum content sizing alongside explicit widths for sidebars (`var(--fd-sidebar-col)`), article bounds, and table of contents columns (`var(--fd-toc-width)`). Depending on `nav.mode`, header positions swap between top grid areas and standard placement.

| Grid Variable | Source Formula / Value | Purpose |
| :--- | :--- | :--- |
| `pageCol` | `calc(var(--fd-layout-width,97rem) - var(--fd-sidebar-col) - var(--fd-toc-width))` | Dynamic column span for the central document area |
| `--fd-sidebar-col` | `collapsed ? '0px' : 'var(--fd-sidebar-width)'` | Active width allocated to the navigation sidebar column |
| `--fd-docs-row-1` | `var(--fd-banner-height, 0px)` | Top vertical offset tracking optional banner height |
| `--fd-docs-row-2` | `calc(var(--fd-docs-row-1) + var(--fd-header-height))` | Vertical row boundary tracking sticky header placement |
| `--fd-docs-row-3` | `calc(var(--fd-docs-row-2) + var(--fd-toc-popover-height))` | Vertical boundary for TOC mobile popover regions |

Sources: [packages/radix-ui/src/layouts/notebook/slots/container.tsx:12-42](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/container.tsx#L12-L42), [packages/base-ui/src/layouts/notebook/slots/container.tsx:12-42](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/slots/container.tsx#L12-L42)

> [!WARNING]
> The container enables grid template transitions only when `data-column-changed` is active (`data-[column-changed=true]:transition-[grid-template-columns]`). Direct mutation of `collapsed` without updating `previousCollapsed` via the layout effect will skip the column width animation frame.
Sources: [packages/radix-ui/src/layouts/notebook/slots/container.tsx:19-47](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/slots/container.tsx#L19-L47), [packages/base-ui/src/layouts/notebook/slots/container.tsx:19-47](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/slots/container.tsx#L19-L47)

### Article Wrapper and Slot Integration

The page container slot (`<article id="nd-page">`) structures individual documentation pages across notebook and flux layouts, binding `[grid-area:main]` to position itself correctly inside the CSS grid. It reads `full` boolean state from `useDocsPage()` to govern maximum width constraints, applying standard typography padding and responsive gaps.

```tsx
export function Container(props: ComponentProps<'article'>) {
  const { full } = useDocsPage();

  return (
    <article
      id="nd-page"
      data-full={full}
      {...props}
      className={cn(
        'flex flex-col [grid-area:main] px-4 py-6 gap-4 md:px-6 md:pt-8 xl:px-8 xl:pt-14 *:max-w-[900px]',
        full && '*:max-w-[1285px]',
        props.className,
      )}
```
Sources: [packages/radix-ui/src/layouts/notebook/page/slots/container.tsx:7-19](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/page/slots/container.tsx#L7-L19), [packages/base-ui/src/layouts/notebook/page/slots/container.tsx:6-18](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/page/slots/container.tsx#L6-L18), [packages/radix-ui/src/layouts/flux/page/slots/container.tsx:7-19](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/page/slots/container.tsx#L7-L19)

Within `DocsPage`, optional slots such as breadcrumbs and footers are conditionally mounted alongside children inside the article container. Table of contents providers wrap the entire page structure, managing TOC item propagation based on `tocEnabled` and `tocPopoverEnabled` flags.

| Layout Variant | Container Max-Width (Standard) | Container Max-Width (`full: true`) | Grid Area Binding |
| :--- | :--- | :--- | :--- |
| Notebook (`radix-ui` / `base-ui`) | `*:max-w-[900px]` | `*:max-w-[1285px]` | `[grid-area:main]` |
| Flux (`radix-ui`) | `max-w-[900px]` | `max-w-[1200px]` | `[grid-area:main]` |

Sources: [packages/radix-ui/src/layouts/notebook/page/slots/container.tsx:15-18](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/page/slots/container.tsx#L15-L18), [packages/base-ui/src/layouts/notebook/page/slots/container.tsx:15-16](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/notebook/page/slots/container.tsx#L15-L16), [packages/radix-ui/src/layouts/flux/page/slots/container.tsx:16-17](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/page/slots/container.tsx#L16-L17)

> [!TIP]
> Setting `full={true}` on `DocsPage` overrides standard child constraints, expanding maximum child widths up to `1285px` in notebook layouts and `1200px` in flux layouts while automatically disabling default desktop TOC rendering unless explicitly re-enabled.
Sources: [packages/radix-ui/src/layouts/notebook/page/index.tsx:103-104](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/page/index.tsx#L103-L104), [packages/radix-ui/src/layouts/notebook/page/slots/container.tsx:15-18](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/notebook/page/slots/container.tsx#L15-L18), [packages/radix-ui/src/layouts/flux/page/slots/container.tsx:16-17](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/radix-ui/src/layouts/flux/page/slots/container.tsx#L16-L17)

## Article Footers and Pagination Controls

### Footer Item Resolution and Active Route Matching

The pagination footer system is driven by the `Footer` component, which accepts explicit pagination items or automatically discovers them using `useFooterItems()` and the current router `pathname`. When explicit `items` are not passed as props, the component finds the active index within the footer list by matching items against the current pathname using `isActive(item.url, pathname)`.

```tsx
export function Footer({ items, children, className, ...props }: FooterProps) {
  const footerList = useFooterItems();
  const pathname = usePathname();
  const { previous, next } = useMemo(() => {
    if (items) return items;

    const idx = footerList.findIndex((item) => isActive(item.url, pathname));

    if (idx === -1) return {};
    return {
      previous: footerList[idx - 1],
      next: footerList[idx + 1],
    };
  }, [footerList, items, pathname]);
```
Sources: [packages/base-ui/src/layouts/flux/page/slots/footer.tsx:25-38](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/page/slots/footer.tsx#L25-L38)

If no matching route is found (`idx === -1`), pagination objects are omitted entirely. Otherwise, `previous` maps to `footerList[idx - 1]` and `next` maps to `footerList[idx + 1]`.

> [!WARNING]
> If `isActive` fails to resolve the current pathname against any entry in `footerList`, both previous and next pagination slots remain undefined, rendering an empty container grid unless explicit items are provided via props.
Sources: [packages/base-ui/src/layouts/flux/page/slots/footer.tsx:28-38](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/page/slots/footer.tsx#L28-L38)

### Container Layout and Pagination Item Rendering

The footer wrapper applies a container query (`@container`) and dynamically toggles CSS grid columns based on the presence of adjacent navigation links. When both previous and next items exist, it assigns `grid-cols-2`; otherwise, it falls back to a single column layout (`grid-cols-1`).

```tsx
  return (
    <>
      <div
        className={cn(
          '@container grid gap-4',
          previous && next ? 'grid-cols-2' : 'grid-cols-1',
          className,
        )}
        {...props}
      >
        {previous && <FooterItem item={previous} index={0} />}
        {next && <FooterItem item={next} index={1} />}
      </div>
      {children}
    </>
  );
}
```
Sources: [packages/base-ui/src/layouts/flux/page/slots/footer.tsx:40-56](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/page/slots/footer.tsx#L40-L56)

Individual footer links are rendered through the `FooterItem` subcomponent, which uses `useTranslations({ note: 'pagination' })` to supply localized fallback text (`Previous Page` or `Next Page`) when an item lacks an explicit description. The icon and text layout adapt based on the index: index `0` (previous) renders a left chevron (`ChevronLeft`) with standard alignment, while index `1` (next) reverses the flex-row direction, right-aligns the text, and renders a right chevron (`ChevronRight`).

| Index | Direction | Icon | Default Description Fallback | CSS Alignment Classes |
| :--- | :--- | :--- | :--- | :--- |
| `0` (Previous) | Standard | `ChevronLeft` | `t('Previous Page')` | `flex flex-col gap-2` |
| `1` (Next) | Reversed (`flex-row-reverse`) | `ChevronRight` | `t('Next Page')` | `flex flex-col gap-2 text-end` |

Sources: [packages/base-ui/src/layouts/flux/page/slots/footer.tsx:58-83](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/base-ui/src/layouts/flux/page/slots/footer.tsx#L58-L83)

## Related

- [Ui Layouts Layout](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/ui-layouts/ui-layouts-layout)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/llms.txt) for all pages in this wiki.
