How to Customize a Docusaurus Theme Using Swizzling: The Complete Guide
Use the docusaurus swizzle CLI command to copy theme components into your site's src/theme folder, allowing you to override or extend the default React components while maintaining upgrade compatibility.
This guide explains how to customize Docusaurus theme components using the swizzling architecture implemented in the facebook/docusaurus repository. Whether you need to tweak the navigation bar, modify the footer, or restructure documentation layouts, swizzling provides a safe mechanism to inject your own React code without forking the entire theme.
What Is Theme Swizzling in Docusaurus?
Docusaurus themes (such as @docusaurus/theme-classic) are distributed as plugins that expose React components through virtual modules aliased as @theme/*. When you customize Docusaurus theme using swizzling, you extract specific components from the theme package into your local src/theme directory, where Docusaurus's Webpack configuration (packages/docusaurus/src/webpack/aliases/index.ts) prioritizes your versions over the originals.
The architecture distinguishes between safe and unsafe components. Safe components, defined in packages/docusaurus-theme-classic/src/getSwizzleConfig.ts, maintain backward compatibility across minor releases, while unsafe components require the --danger flag and may break during upgrades.
How the Swizzle Command Works
The swizzle CLI implementation resides in packages/docusaurus/src/commands/swizzle/index.ts, which parses arguments and validates component selections against the safety configuration. When you execute a swizzle command, packages/docusaurus/src/commands/swizzle/components.ts handles the file generation logic, computing component paths and applying either wrap or eject actions.
Wrap mode (recommended) creates a wrapper component that imports the original via @theme-original/*, allowing you to augment functionality while delegating rendering to the upstream version. Eject mode copies the source file verbatim, giving you full control but requiring manual maintenance when the theme updates.
Customizing Docusaurus Theme Components Step-by-Step
Finding Components to Swizzle
First, identify the component you want to override. You can browse the theme source code or use the interactive CLI:
npx docusaurus swizzle
This command displays all available components from installed themes, indicating which are safe to swizzle according to the configuration in getSwizzleConfig.ts.
Choosing Between Wrap and Eject
Select the appropriate swizzling strategy based on your customization needs:
- Wrap: Use this for additive changes (injecting props, wrapping in HOCs, adding analytics). The generated file imports from
@theme-original/ComponentName, ensuring you receive upstream bug fixes automatically.
npx docusaurus swizzle @docusaurus/theme-classic Footer --wrap
- Eject: Use this when you must fundamentally rewrite the component's render logic. You assume full maintenance responsibility for the component file.
npx docusaurus swizzle @docusaurus/theme-classic BlogPostItem --eject
Editing Swizzled Components
After running the command, find your new component in src/theme/. For example, a wrapped Footer component looks like this:
// src/theme/Footer/index.tsx
import React from 'react';
import OriginalFooter from '@theme-original/Footer';
import MyLogo from '@site/static/img/my-logo.svg';
export default function Footer(props) {
return (
<div>
<MyLogo className="myFooterLogo" />
<OriginalFooter {...props} />
</div>
);
}
The Webpack alias system ensures that @theme/Footer now resolves to your local file, while @theme-original/Footer continues to point to the theme's built-in version.
Handling Unsafe Components
Some internal components (like DocItem) are marked unsafe because their APIs may change. To swizzle these, add the --danger flag:
npx docusaurus swizzle @docusaurus/theme-classic DocItem --wrap --danger
As implemented in packages/docusaurus/src/commands/swizzle/index.ts, the CLI will prompt for confirmation if you omit the flag, warning you about potential breaking changes during upgrades.
Practical Examples of Docusaurus Theme Swizzling
Wrapping a NavbarItem with a Tooltip
This example demonstrates extending a safe component to inject Material-UI tooltips:
npx docusaurus swizzle @docusaurus/theme-classic NavbarItem --wrap
// src/theme/NavbarItem/index.tsx
import React from 'react';
import OriginalNavbarItem from '@theme-original/NavbarItem';
import Tooltip from '@mui/material/Tooltip';
export default function NavbarItem(props) {
return (
<Tooltip title="Custom tooltip" placement="bottom">
<OriginalNavbarItem {...props} />
</Tooltip>
);
}
Ejecting a BlogPostItem for Complete Customization
When you need to restructure the blog post layout entirely:
npx docusaurus swizzle @docusaurus/theme-classic BlogPostItem --eject
// src/theme/BlogPostItem/index.tsx
import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
export default function BlogPostItem({content}) {
return (
<article className={clsx('customBlogPostItem')}>
<h2>{content.title}</h2>
<p className="customExcerpt">{content.description}</p>
<Link to={content.permalink}>Read Custom Styled Post →</Link>
</article>
);
}
Summary
- Swizzling exports theme components from
@docusaurus/theme-classic(or other themes) into your localsrc/themedirectory for customization. - The CLI implementation in
packages/docusaurus/src/commands/swizzle/index.tsorchestrates the process, whilecomponents.tshandles file generation. - Wrap mode preserves upgrade safety by importing the original component via
@theme-original/*, whereas eject mode copies the source directly. - Safe components are guaranteed compatible across minor releases; unsafe components require
--dangerand manual maintenance. - Webpack aliases configured in
packages/docusaurus/src/webpack/aliases/index.tsensure your local files override theme defaults.
Frequently Asked Questions
What is the difference between wrap and eject when customizing Docusaurus themes?
Wrap mode creates a wrapper component that renders the original theme component as a child, allowing you to inject logic or styling while automatically receiving upstream bug fixes. Eject mode copies the entire source code of the component into your project, giving you complete control over the implementation but requiring you to manually merge changes when upgrading Docusaurus.
Are swizzled components safe to use across Docusaurus upgrades?
It depends on the component's safety classification. Components marked as safe in packages/docusaurus-theme-classic/src/getSwizzleConfig.ts maintain stable APIs across minor versions, making upgrades seamless. Unsafe components may undergo breaking changes in any release; if you swizzle these, monitor the Docusaurus changelog and test thoroughly after updating.
How does Docusaurus prioritize my swizzled components over the default theme?
Docusaurus configures Webpack aliases in packages/docusaurus/src/webpack/aliases/index.ts to resolve @theme/* imports to your local src/theme directory before falling back to the node_modules theme package. When using wrap mode, the system also creates an @theme-original/* alias that points to the genuine theme component, allowing your wrapper to import the base implementation.
Can I swizzle multiple components or entire theme sections at once?
The CLI operates on individual components to ensure intentional customization decisions. While you can run the swizzle command multiple times for different components, you cannot bulk-eject entire directories. This granular approach, enforced by the component resolution logic in packages/docusaurus/src/commands/swizzle/components.ts, prevents accidental maintenance burdens from unnecessary ejections.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →