Skip to main content

Tutorial Docusaurus React Live

· 4 min read ·
Docux
Curious explorer, a bit of a mad experimenter, and a bit of a contributor.

1. Why I added a playground

I wanted readers to learn faster by allowing them to modify examples inline. The @docusaurus/theme-live-codeblock theme integrates react-live to evaluate JSX in real time.

Benefits I gained:

  • Instant feedback for readers
  • Pedagogical demos without an external sandbox
  • Visual consistency with the site
  • No page context switching

2. Install the live theme

> user@machine: ~/yourproject

npm install @docusaurus/theme-live-codeblock --save

note

Ensure all @docusaurus/* versions are aligned (e.g. 3.9.1).

3. Configure docusaurus.config.js

Add (or extend) the themes key:

docusaurus.config.js
export default {
// ...other options
themes: ["@docusaurus/theme-live-codeblock"],
};

Optional: adjust styling with custom CSS (Infima is bundled).

4. Create your first jsx live blocks

A MDX fenced block becomes interactive by adding live after the language:

```jsx live
() => <button style={{ padding: 8 }}>Click me</button>;
```

You can also write a function:

```jsx live
function Counter() {
const [n, setN] = React.useState(0);
return <button onClick={() => setN(n + 1)}>Count: {n}</button>;
}
<Counter />;
```

5. Effective patterns

PatternUse caseBenefitExample
Final expressionTiny demoUltra concise(<Badge>Hi</Badge>)
Const + final identifierReadable snippetShows valueconst el=<div/>; el
Function + callInternal logicReusablefunction Demo(){...}; <Demo />
Inline hooksSmall interactionsDirectconst [x,setX]=useState(0); <button onClick={()=>setX(x+1)}>{x}
Export default (avoid)Legacy habitNoise here(do not use)

Key rule: the last expression of the block is rendered (no export).

6. Swizzle ReactLiveScope

Problem: inside a live block, your custom components (Tooltip, LogoIcon, etc.) are not known by default.

Solution: create src/theme/ReactLiveScope/index.js to inject a global scope.

import * as React from "react";

// @ts-ignore
import Tooltip from "@site/src/components/Tooltip";
import LogoIcon from "@site/src/components/LogoIcon";
import Skill from "@site/src/components/Skill";
import Contributor from "@site/src/components/Contributor";
import Columns from "@site/src/components/Columns";
import TimeTimer, {
FallbackBefore,
FallbackAfter,
} from "@site/src/components/TimeTimer";
import Column from "@site/src/components/Column";
import Card from "@site/src/components/Card";
import CardBody from "@site/src/components/Card/CardBody";
import CardFooter from "@site/src/components/Card/CardFooter";
import CardHeader from "@site/src/components/Card/CardHeader";
import CardImage from "@site/src/components/Card/CardImage";
// Export only the symbols the react-live runtime needs to evaluate snippets.
const {
useState,
useEffect,
useRef,
useMemo,
useCallback,
Fragment,
forwardRef,
createElement,
Children,
} = React;

export default {
// Keep the complete React object accessible if needed (without spread to avoid 'default' key)
React,
// Frequently used hooks in snippets
useState,
useEffect,
useRef,
useMemo,
useCallback,
Fragment,
forwardRef,
createElement,
Children,
// Custom components exposed in live blocks
Tooltip,
LogoIcon,
Skill,
Contributor,
TimeTimer,
FallbackBefore,
FallbackAfter,
Columns,
Column,
Card,
CardBody,
CardFooter,
CardHeader,
CardImage,
// HTML elements
center: "center",
};

From there on:

Live Editor
<Tooltip model="teacher" text="DocuxLab">
  Swizzle ready!
</Tooltip>
Result
Loading...

7. Advanced examples: interactive Tooltip

Simple model

Live Editor
<Tooltip text="Simple tooltip">Short content.</Tooltip>
Result
Loading...

Two tooltips side by side

Live Editor
<div style={{ display: "flex", gap: 16 }}>
  <Tooltip model="teacher" text="Teacher">
    Example with model.
  </Tooltip>
  <Tooltip model="suricate" text="Pépé" position="bottom">
    Bottom position.
  </Tooltip>
</div>
Result
Loading...

Skill (progress bar)

Live Editor
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
  <Skill
    name={
      <>
        <LogoIcon name="react" size="24" /> React
      </>
    }
    value={88}
    type="bar"
    color="#61DAFB"
    height={25}
  />
  <Skill
    name={
      <>
        <LogoIcon name="vue" size="24" /> Vue.js
      </>
    }
    value={75}
    type="bar"
    color="#4FC08D"
    height={25}
  />
  <Skill
    name={
      <>
        <LogoIcon name="nodejs" size="24" /> Node.js
      </>
    }
    value={82}
    type="bar"
    color="#339933"
    height={25}
  />
  <Skill
    name={
      <>
        <LogoIcon name="python" size="24" /> Python
      </>
    }
    value={78}
    type="bar"
    color="#3776AB"
    height={25}
  />
</div>
Result
Loading...

Skill (animated circle)

Live Editor
<div
  style={{
    display: "grid",
    gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))",
    gap: "20px",
    marginTop: "20px",
  }}
>
  <Skill
    name={
      <>
        <LogoIcon name="html-5" size="24" />{" "}
      </>
    }
    value={95}
    type="circle"
    color="#E34F26"
    valuePosition="center"
    size={100}
  />
  <Skill
    name={
      <>
        <LogoIcon name="css-3" size="24" />{" "}
      </>
    }
    value={90}
    type="circle"
    color="#1572B6"
    valuePosition="center"
    size={100}
  />
  <Skill
    name={
      <>
        <LogoIcon name="javascript" size="24" />{" "}
      </>
    }
    value={85}
    type="circle"
    color="#F7DF1E"
    valuePosition="center"
    size={100}
  />
</div>
Result
Loading...

Contributor (card)

Live Editor
<Contributor
  name="Docux"
  github="Juniors017"
  website="https://github.com/Juniors017"
  avatarUrl="/img/docux.webp"
  components={["Tooltip", "Skill", "etc..."]}
  description="Author of several UI components for this site."
/>
Result
Loading...

LogoIcon (variants)

Live Editor
<div style={{ display: "flex", gap: 24, alignItems: "center" }}>
  <LogoIcon name="docusaurus" size={40} />
  <LogoIcon name="javascript" size={40} />
  <LogoIcon name="css-3" size={40} />
</div>
Result
Loading...

8. Best practices

  • Keep snippets short and progressive.
  • Do not overload the scope (clarity + performance).
  • Watch for CSS collisions (avoid heavy globals).
  • Prefer an explicit final expression for readability.
  • Update @docusaurus/* dependencies together.

9. Quick debugging

IssueLikely causeFix
X is not definedComponent not in scopeAdd to ReactLiveScope
Nothing displayedNo final expressionEnd with JSX or identifier
React import crashUnnecessary importRemove import React
Broken styleInfima/custom conflictWrap / isolate
Versions mismatchMisaligned packagesAlign versions

10. Going further

Ideas:

  • Add a light/dark theme toggle inside demos.
  • Persist state (localStorage) in a live block.
  • Generate dynamic component variations.
Your turn!

No related posts.

Back to top