Swizzling
In this section, we will introduce how customization of layout is done in Docusaurus.
DΓ©jΓ vu...?
This section is similar to Styling and Layout, but this time, we will customize React components themselves, rather than what they look like. We will talk about a central concept in Docusaurus: swizzling, which allows deeper site customizations.
In practice, swizzling permits to swap a theme component with your own implementation, and it comes in 2 patterns:
- Ejecting: creates a copy of the original theme component, which you can fully customize
- Wrapping: creates a wrapper around the original theme component, which you can enhance
Why is it called swizzling?
The name comes from Objective-C and Swift-UI: method swizzling is the process of changing the implementation of an existing selector (method).
For Docusaurus, component swizzling means providing an alternative component that takes precedence over the component provided by the theme.
You can think of it as Monkey Patching for React components, enabling you to override the default implementation. Gatsby has a similar concept called theme shadowing.
To gain a deeper understanding of this, you have to understand how theme components are resolved.
Swizzling Process
Section titled βSwizzling ProcessβOverview
Section titled βOverviewβDocusaurus provides a convenient interactive CLI to swizzle components. You generally only need to remember the following command:
npm run swizzleIt will generate a new component in your src/theme directory, which should look like this example:
<Tabs>
<TabItem value="Ejecting">import React from 'react';
export default function SomeComponent(props) {
// You can fully customize this implementation
// including changing the JSX, CSS and React hooks
return (
<div className="some-class">
<h1>Some Component</h1>
<p>Some component implementation details</p>
</div>
);
}</TabItem>
<TabItem value="Wrapping">import React from 'react';
import SomeComponent from '@theme-original/SomeComponent';
export default function SomeComponentWrapper(props) {
// You can enhance the original component,
// including adding extra props or JSX elements around it
return (
<>
<SomeComponent {...props} />
</>
);
}</TabItem>
</Tabs>To get an overview of all the themes and components available to swizzle, run:
npm run swizzle -- --listUse --help to see all available CLI options, or refer to the reference swizzle CLI documentation.
Ejecting
Section titled βEjectingβEjecting a theme component is the process of creating a copy of the original theme component, which you can fully customize and override.
To eject a theme component, use the swizzle CLI interactively, or with the --eject option:
npm run swizzle [theme name] [component name] -- --ejectAn example:
npm run swizzle @docusaurus/theme-classic Footer -- --ejectThis will copy the current <Footer /> component's implementation to your site's src/theme directory. Docusaurus will now use this <Footer> component copy instead of the original one. You are now free to completely re-implement the <Footer> component.
import React from 'react';
export default function Footer(props) {
return (
<footer>
<h1>This is my custom site footer</h1>
<p>And it is very different from the original</p>
</footer>
);
}Wrapping
Section titled βWrappingβWrapping a theme component is the process of creating a wrapper around the original theme component, which you can enhance.
To wrap a theme component, use the swizzle CLI interactively, or with the --wrap option:
npm run swizzle [theme name] [component name] -- --wrapAn example:
npm run swizzle @docusaurus/theme-classic Footer -- --wrapThis will create a wrapper in your site's src/theme directory. Docusaurus will now use the <FooterWrapper> component instead of the original one. You can now add customizations around the original component.
import React from 'react';
import Footer from '@theme-original/Footer';
export default function FooterWrapper(props) {
return (
<>
<section>
<h2>Extra section</h2>
<p>This is an extra section that appears above the original footer</p>
</section>
<Footer {...props} />
</>
);
}What is this @theme-original thing?
Docusaurus uses theme aliases to resolve the theme components to use. The newly created wrapper takes the @theme/SomeComponent alias. @theme-original/SomeComponent permits to import original component that the wrapper shadows without creating an infinite import loop where the wrapper imports itself.
What is safe to swizzle?
Section titled βWhat is safe to swizzle?βWith great power comes great responsibility
Some theme components are internal implementation details of a theme. Docusaurus allows you to swizzle them, but it might be risky.
Why is it risky?
Theme authors (including us) might have to update their theme over time: changing the component props, name, file system location, types... For example, consider a component that receives two props name and age, but after a refactor, it now receives a person prop with the above two properties. Your component, which still expects these two props, will render undefined instead.
Moreover, internal components may simply disappear. If a component is called Sidebar and it's later renamed to DocSidebar, your swizzled component will be completely ignored.
Theme components marked as unsafe may change in a backward-incompatible way between theme minor versions. When upgrading a theme (or Docusaurus), your customizations might behave unexpectedly, and can even break your site.
For each theme component, the swizzle CLI will indicate 3 different levels of safety declared by theme authors:
- Safe: this component is safe to be swizzled, its public API is considered stable, and no breaking changes should happen within a theme major version
- Unsafe: this component is a theme implementation detail, not safe to be swizzled, and breaking changes might happen within a theme minor version
- Forbidden: the swizzle CLI will prevent you from swizzling this component, because it is not designed to be swizzled at all
Which component should I swizzle?
Section titled βWhich component should I swizzle?βIt is not always clear which component you should swizzle exactly to achieve the desired result. @docusaurus/theme-classic, which provides most of the theme components, has about 100 components!
You can follow these steps to locate the appropriate component to swizzle:
- Component description. Some components provide a short description, which is a good way to find the right one.
- Component name. Official theme components are semantically named, so you should be able to infer its function from the name. The swizzle CLI allows you to enter part of a component name to narrow down the available choices. For example, if you run
yarn swizzle @docusaurus/theme-classic, and enterDoc, only the docs-related components will be listed. - Start with a higher-level component. Components form a tree with some components importing others. Every route will be associated with one top-level component that the route will render (most of them listed in Routing in content plugins). For example, all blog post pages have
@theme/BlogPostPageas the topmost component. You can start with swizzling this component, and then go down the component tree to locate the component that renders just what you are targeting. Don't forget to unswizzle the rest by deleting the files after you've found the correct one, so you don't maintain too many components. - Read the theme source code and use search wisely.
Do I need to swizzle?
Section titled βDo I need to swizzle?βSwizzling ultimately means you have to maintain some additional React code that interact with Docusaurus internal APIs. If you can, think about the following alternatives when customizing your site:
- Use CSS. CSS rules and selectors can often help you achieve a decent degree of customization. Refer to styling and layout for more details.
- Use translations. It may sound surprising, but translations are ultimately just a way to customize the text labels. For example, if your site's default language is
en, you can still runyarn write-translations -l enand edit thecode.jsonemitted. Refer to the i18n tutorial for more details.
Wrapping your site with <Root>
Section titled βWrapping your site with <Root>βThe <Root> component is rendered at the very top of the React tree, above the theme <Layout>, and never unmounts. It is the perfect place to add stateful logic that should not be re-initialized across navigations (user authentication status, shopping cart state...).
Swizzle it manually by creating a file at src/theme/Root.js:
import React from 'react';
// Default implementation, that you can customize
export default function Root({children}) {
return <>{children}</>;
}