Live code editing in docusaurus - UX at its best
Tags: markdown, mdx, reactlive, docusaurus
Published: 2020-08-22 16:08:52

> Docusaurus is a tool designed to make it easy for teams to publish documentation websites without having to worry about the infrastructure and design details.

[Docusaurus 2](https://v2.docusaurus.io/) is bringing a lot of new features with it but my most favorite one is **[live code editing](https://v2.docusaurus.io/docs/markdown-features#interactive-code-editor)**. It lets you preview your changes at run-time without switching your context which gives you a really good user experience.

## Installation
There is an official plugin to enable live code editing in your website, i.e. [@docusaurus/theme-live-codeblock](https://v2.docusaurus.io/docs/using-themes#docusaurustheme-live-codeblock). This theme provides a `@theme/CodeBlock` component that is powered by [react-live](https://react-live.netlify.com/).
First, install the plugin in your website.
```bash
yarn add @docusaurus/theme-live-codeblock
```
You will also need to add the plugin to your `docusaurus.config.js`.
```js
module.exports = {
  // ...
  themes: ['@docusaurus/theme-live-codeblock'],
  // ...
};
```

## Usage
To use the plugin, create a code block with live attached to the language meta string.
    ```jsx live
    function Clock(props) {
      const [date, setDate] = useState(new Date());
      useEffect(() => {
        var timerID = setInterval(() => tick(), 1000);

        return function cleanup() {
          clearInterval(timerID);
        };
      });

      function tick() {
        setDate(new Date());
      }

      return (
        <div>
          <h2>It is {date.toLocaleTimeString()}.</h2>
        </div>
      );
    }
    ```
The code block will be rendered as an interactive editor. Changes to the code will reflect on the result panel live.
### Third-party Components
By default `React` is in scope of live code blocks in MDX files but in order to render third-party components we need to add those components in the scope by swizzling the default theme, i.e. `@docusaurus/theme-classic`.
To swizzle a component for a theme, run the following command in your doc site:
```sh
docusaurus swizzle <theme name> [component name]
```
In our case, theme name is `@docusaurus/theme-classic` and component name is `MDXComponents`:
```sh
yarn swizzle @docusaurus/theme-classic MDXComponents
```
It'll copy the `MDXComponents` folder to `src/themes`. Let's say we want to render `Button` from [material-ui](https://material-ui.com/components/buttons/), so we'll have to update the `index.js` file and add `Button` in the `scope` of `CodeBlock` component:
```diff
// ... imports

+ import Button from "@material-ui/core/Button";

export default {
  code: props => {
    const { children } = props;
    if (typeof children === "string") {
-      return <CodeBlock {...props} />;
+      return <CodeBlock {...props} scope={{ Button }} />;
    }
    return children;
  },

  // ...

};
```
Now, in your live code block you can just use the `Button` component which will render button from `material-ui`:
    ```jsx live
    function MuiButton() {
      return (
        <Button variant="contained" color="primary">
          Primary
        </Button>
      );
    }
    ```
You can also add the whole package in `scope` but that'll increase your bundle size even if you're not using most of the components, so I'd prefer optimized imports and adding the only components which are being used.

## Customization
In order to customize the design / implementation of the code block and code preview we'll swizzle the theme:
```sh
yarn swizzle @docusaurus/theme-live-codeblock Playground
```
Let's change orientation of the playground by editing `src/themes/Playground/index.js`:
```jsx
// ...

<LiveProvider
  code={children.replace(/\n$/, "")}
  transformCode={transformCode || (code => `${code};`)}
  theme={theme}
  {...props}
>
  <div className={styles.playgroundPreview}>
    <LivePreview />
    <LiveError />
  </div>
  <div
    className={classnames(
      styles.playgroundHeader,
      styles.playgroundEditorHeader,
    )}
  >
    Live Editor
  </div>
  <LiveEditor />
</LiveProvider>

// ...
```
You can customize this file as you like, I just wanted to demonstrate how easily you can do that.

## Caution
Docusaurus team discourages the usage of swizzle so use it with caution:
> We would like to discourage swizzling of components until we've minimally reached a Beta stage. The components APIs have been changing rapidly and are likely to keep changing until we reach Beta. Stick with the default appearance for now if possible to save yourself some potential pain in future.

- _Some documentation part of the article is copied from [official docs](https://v2.docusaurus.io/docs/markdown-features#interactive-code-editor) of docusaurus._
- _And thanks to Johnny's [comment](https://github.com/facebook/docusaurus/issues/2152#issuecomment-597558963) which saved me from more digging regarding scope of code block._