---
title: "Base Components"
description: "Base Components constitute the foundational UI building blocks in the Fumadocs architecture, designed to provide a consistent, reusable, and accessible interface for documentation sites. These comp..."
last_updated: "2026-07-02T09:46:39.333443+00:00"
canonical_url: "https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/rendering-ui/base-components"
---

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

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

- [packages/radix-ui/src/components/sidebar/base.tsx](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/sidebar/base.tsx)
- [packages/base-ui/src/components/sidebar/base.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/sidebar/base.tsx)
- [packages/base-ui/package.json](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/package.json)
- [packages/base-ui/src/components/tabs.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/tabs.tsx)
- [packages/base-ui/src/layouts/notebook/slots/sidebar.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/layouts/notebook/slots/sidebar.tsx)
- [packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/layouts/notebook/slots/sidebar.tsx)
- [packages/sanity/registry/base.component.tsx](https://github.com/blade47/fumadocs/blob/main/packages/sanity/registry/base.component.tsx)
- [packages/api-docs/src/components/accordion.tsx](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/components/accordion.tsx)
- [packages/base-ui/src/components/image-zoom.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/image-zoom.tsx)
- [packages/base-ui/src/components/codeblock.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/codeblock.tsx)
- [packages/base-ui/src/mdx.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/mdx.tsx)
- [packages/radix-ui/src/components/image-zoom.tsx](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/image-zoom.tsx)
- [packages/radix-ui/src/components/codeblock.tsx](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/codeblock.tsx)
- [packages/base-ui/src/components/accordion.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/accordion.tsx)
- [packages/base-ui/src/components/callout.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/callout.tsx)
- [packages/radix-ui/src/mdx.tsx](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/mdx.tsx)
- [packages/radix-ui/src/components/accordion.tsx](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/accordion.tsx)
- [packages/sanity/registry/accordion.component.tsx](https://github.com/blade47/fumadocs/blob/main/packages/sanity/registry/accordion.component.tsx)
- [packages/base-ui/src/components/ui/tabs.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/ui/tabs.tsx)
- [packages/radix-ui/src/components/callout.tsx](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/callout.tsx)
- [packages/sanity/registry/steps.component.tsx](https://github.com/blade47/fumadocs/blob/main/packages/sanity/registry/steps.component.tsx)
- [packages/sanity/registry/tabs.component.tsx](https://github.com/blade47/fumadocs/blob/main/packages/sanity/registry/tabs.component.tsx)
- [packages/openapi/src/ui/base.tsx](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/ui/base.tsx)
- [packages/sanity/registry/files.component.tsx](https://github.com/blade47/fumadocs/blob/main/packages/sanity/registry/files.component.tsx)
- [packages/python/src/components/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/python/src/components/index.tsx)
- [packages/base-ui/registry/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/registry/index.ts)
- [packages/base-ui/src/components/ui/accordion.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/ui/accordion.tsx)
- [packages/core/src/mdx-plugins/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/core/src/mdx-plugins/index.ts)
- [packages/base-ui/src/components/steps.tsx](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/steps.tsx)
- [packages/radix-ui/registry/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/registry/index.ts)
</details>

Base Components constitute the foundational UI building blocks in the Fumadocs architecture, designed to provide a consistent, reusable, and accessible interface for documentation sites. These components abstract low-level primitives into domain-specific modules like sidebars, code blocks, and interactive tabs, ensuring that functionality remains decoupled from specific layout implementations. By standardizing these components, the system facilitates rapid development of documentation layouts while maintaining a high degree of customizability.

At the core of these components is a focus on "mechanism over style." Many components rely on context providers (`SidebarContext`, `TabsContext`, `FolderContext`) to share state across deep component hierarchies, allowing for behaviors like automatic scrolling, shared keyboard navigation, and synced UI states. This architecture enables developers to compose complex documentation features (such as collapsible navigation trees) without manual state management.

The system is split into two primary implementation tiers: `base-ui` and `radix-ui`. While they share identical external APIs and shared logic, the `radix-ui` variant leverages Radix UI primitives, providing a different set of underlying behaviors and accessibility features compared to the standard `base-ui` implementation. This duality ensures that Fumadocs can support diverse technical requirements while maintaining a unified interface for the developer.

## Sidebar Architecture and State Management

The sidebar system is a complex subsystem composed of providers and specialized slots. It manages navigation state, responsive behaviors (drawer vs. full-width), and folder expansion. The state is maintained in `SidebarContext` and `FolderContext`, allowing nested components like `SidebarFolder`, `SidebarItem`, and `SidebarTrigger` to react to global changes in the sidebar state.

The core mechanism for responsiveness relies on `useMediaQuery` to toggle between `drawer` and `full` modes. In drawer mode, the sidebar uses an overlay element managed by `Presence` to handle animations.

```mermaid
flowchart TD
    A["SidebarProvider"] --> B["SidebarContext (Global State)"]
    B --> C["SidebarContent"]
    B --> D["SidebarDrawerOverlay"]
    D --> E["Presence (Animation)"]
    F["SidebarFolder"] --> G["FolderContext (Hierarchical Depth)"]
    G --> H["SidebarFolderTrigger"]
    G --> I["SidebarFolderContent"]
    I --> J["SidebarFolderLink"]
```
Sources: [packages/radix-ui/src/components/sidebar/base.tsx:32-45](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/sidebar/base.tsx#L32-L45), [packages/radix-ui/src/components/sidebar/base.tsx:75-112](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/sidebar/base.tsx#L75-L112)

> [!TIP]
> Use the `defaultOpenLevel` prop in `SidebarProvider` to control the initial expansion state of folders. Folders with a depth less than or equal to this level will automatically initialize as expanded.

## Tab Collection Logic

The `Tabs` component implements a robust collection mechanism inspired by Headless UI to handle child order and selection. Instead of relying on manual index management, each `Tab` component uses a unique ID (`useId`) and registers itself into a shared `collection` array held in `TabsContext`.

When `Tab` renders, it calls `useCollectionIndex()` which performs the following logic:
1. Generates a unique ID for the instance.
2. Checks if the ID exists in the collection.
3. If not, pushes it to the collection.
4. Returns the index of the ID within the collection array.

Sources: [packages/base-ui/src/components/tabs.tsx:184-197](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/tabs.tsx#L184-L197)

## Code Block Mechanism and Copy Logic

The `CodeBlock` component handles code highlighting visualization with built-in actions like copying. It leverages `useCopyButton` to orchestrate clipboard interactions. A significant detail in the copying mechanism is the handling of non-copyable elements via `cloneNode`:

- The `containerRef` is used to retrieve the inner `re>` tag.
- `cloneNode(true)` creates a deep clone of the content to avoid modifying the visual DOM.
- The clone traverses its own children to remove nodes marked with the `.nd-copy-ignore` class before executing `navigator.clipboard.writeText`.

```typescript
const [checked, onClick] = useCopyButton(() => {
  const pre = containerRef.current?.getElementsByTagName('pre').item(0);
  if (!pre) return;

  const clone = pre.cloneNode(true) as HTMLElement;
  clone.querySelectorAll('.nd-copy-ignore').forEach((node) => {
    node.replaceWith('\n');
  });

  void navigator.clipboard.writeText(clone.textContent ?? '');
});
```
Sources: [packages/base-ui/src/components/codeblock.tsx:157-167](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/codeblock.tsx#L157-L167)

## Accordion Anchor Integration

The `Accordion` component integrates with the `auto-anchor` system to support deep-linking directly to specific accordion sections. This is implemented via a `useEffect` inside `AccordionItem` that monitors the URL hash and automatically opens the corresponding accordion section if it matches the generated `id`.

The `anchorIdStartsWith` guard is crucial here: it verifies if the hash segment matches the section's ID, preventing arbitrary hash triggers from opening unrelated accordions.

Sources: [packages/api-docs/src/components/accordion.tsx:43-46](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/components/accordion.tsx#L43-L46)

## Sidebar Auto-Scroll Logic

The sidebar uses a custom `useAutoScroll` hook to keep active items in view within the viewport. This is triggered whenever an item becomes `active`. The mechanism calculates the boundary of the sidebar based on its current mode:

- **Drawer Mode:** Targets the element with ID `nd-sidebar-mobile`.
- **Full Mode:** Targets the element with ID `nd-sidebar`.

The `scrollIntoView` library is invoked with `{ scrollMode: 'if-needed' }` to ensure the sidebar does not jitter or force-scroll if the item is already visible.

Sources: [packages/radix-ui/src/components/sidebar/base.tsx:402-410](https://github.com/blade47/fumadocs/blob/main/packages/radix-ui/src/components/sidebar/base.tsx#L402-L410)

## Callout Variant Resolution

Callouts support multiple types, but the implementation allows for aliasing to maintain backwards compatibility or semantic clarity. The `resolveAlias` function handles these mappings before the visual container is rendered:

| Alias | Resolved Value |
| :--- | :--- |
| `warn` | `warning` |
| `tip` | `info` |

The resolve logic ensures that the internal CSS variable `--callout-color` correctly maps to the corresponding theme variable (e.g., `--color-fd-info` or `--color-fd-warning`).

Sources: [packages/base-ui/src/components/callout.tsx:34-38](https://github.com/blade47/fumadocs/blob/main/packages/base-ui/src/components/callout.tsx#L34-L38)

> [!CAUTION]
> Manually overriding `style` on a `CalloutContainer` may break the automatic `--callout-color` calculation. If custom styling is required, use the `className` prop to target the container directly rather than overriding the internal CSS variables.

## Related

- [Syntax Highlighting](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/rendering-ui/syntax-highlighting)


## Sitemap

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