# How to Integrate Mermaid into a React Component Using the Promise-Based API

> Integrate Mermaid into React using the promise-based API. Learn to render SVGs asynchronously with useEffect, manage loading, and use dangerouslySetInnerHTML.

- Repository: [mermaid-js/mermaid](https://github.com/mermaid-js/mermaid)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Use `mermaid.render()` inside a `useEffect` hook to asynchronously generate SVG markup from diagram definitions, then inject the result using `dangerouslySetInnerHTML` while handling loading states and cleanup.**

The mermaid-js/mermaid library provides a client-side JavaScript API that converts text-based diagram definitions into scalable vector graphics. When you integrate Mermaid into a React component, you work with the asynchronous `mermaid.render()` method, which returns a Promise that resolves with the generated SVG string. This approach requires careful management of component lifecycles, cleanup logic, and state updates to prevent memory leaks and ensure smooth re-renders.

## Understanding the Mermaid Render API

According to the source code in [`src/mermaidAPI.js`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.js), the `mermaid.render()` function serves as the primary entry point for generating diagrams programmatically. This method accepts two parameters: a unique string `id` for the diagram instance and the `diagramDefinition` string containing the Mermaid syntax.

The function returns a **Promise** that resolves to an object with the following structure:

- `svg`: The generated SVG markup as a string
- `bindFunctions`: Optional callback for attaching event listeners to diagram elements
- `bindListeners`: Optional callback for additional listener bindings
- `errors`: Array of any parsing or rendering errors encountered

### The Importance of Unique IDs

When calling `mermaid.render(id, definition)`, the `id` parameter must be unique across your application to prevent DOM collisions. In React 18+, use the `useId()` hook to generate stable, unique identifiers for each diagram instance. For older React versions, implement a counter or UUID generator to ensure uniqueness.

## Step-by-Step Integration Guide

To properly integrate Mermaid into a React component, you must initialize the library, handle the asynchronous render cycle, and safely inject the resulting SVG. The implementation in [`src/index.js`](https://github.com/mermaid-js/mermaid/blob/main/src/index.js) exports the public API including `mermaid.initialize` and `mermaid.render`.

### Initializing the Library

Before rendering diagrams, call `mermaid.initialize(options)` once to configure global settings. This function, defined in [`src/initialize.js`](https://github.com/mermaid-js/mermaid/blob/main/src/initialize.js), sets the theme, security level, and other defaults. Pass `startOnLoad: false` when rendering manually within React components to prevent automatic DOM manipulation.

```javascript
import mermaid from 'mermaid'

mermaid.initialize({
  startOnLoad: false,
  theme: 'default',
  securityLevel: 'loose'
})

```

### Handling the Render Promise

Because `mermaid.render()` executes asynchronously, implement cleanup logic to handle component unmounting. Use a `cancelled` flag inside `useEffect` to ignore Promise resolutions after the component has unmounted.

The render process creates a temporary DOM container internally (as implemented in [`src/diagramAPI.js`](https://github.com/mermaid-js/mermaid/blob/main/src/diagramAPI.js)), parses the diagram definition, and generates the SVG markup. This operation relies on `window` and DOM APIs, making it incompatible with server-side rendering unless properly guarded.

## Complete React Component Example

Below is a production-ready React component that safely integrates Mermaid using the Promise-based API:

```jsx
import { useEffect, useState, useId } from 'react'
import mermaid from 'mermaid'

// Initialize once at module level
mermaid.initialize({
  startOnLoad: false,
  theme: 'default'
})

export default function Mermaid({ definition, className = '' }) {
  const [svg, setSvg] = useState('')
  const [error, setError] = useState(null)
  const diagramId = useId()

  useEffect(() => {
    let cancelled = false

    mermaid
      .render(diagramId, definition)
      .then(({ svg }) => {
        if (!cancelled) setSvg(svg)
      })
      .catch((err) => {
        if (!cancelled) setError(err)
        console.error('Mermaid render error:', err)
      })

    return () => {
      cancelled = true
    }
  }, [definition, diagramId])

  if (error) {
    return <pre className={className}>Error rendering diagram: {error.message}</pre>
  }

  return (
    <div
      className={className}
      dangerouslySetInnerHTML={{ __html: svg }}
    />
  )
}

```

## Managing Multiple Diagrams and Dynamic Themes

For applications rendering multiple diagrams or supporting theme switching, batch the render operations using `Promise.all`. The [`src/defaultConfig.js`](https://github.com/mermaid-js/mermaid/blob/main/src/defaultConfig.js) file contains the default theme options that can be overridden via `mermaid.initialize()`.

```jsx
import { useEffect, useState, useId } from 'react'
import mermaid from 'mermaid'

export function MermaidMulti({ diagrams, theme = 'neutral' }) {
  const [svgs, setSvgs] = useState([])
  const componentId = useId()

  useEffect(() => {
    // Re-initialize when theme changes
    mermaid.initialize({ startOnLoad: false, theme })
    
    const promises = diagrams.map((def, idx) => {
      const id = `${componentId}-${idx}`
      return mermaid.render(id, def).then(({ svg }) => ({ id, svg }))
    })

    Promise.all(promises)
      .then((results) => setSvgs(results))
      .catch((err) => console.error('Batch render error:', err))
  }, [diagrams, theme, componentId])

  return (
    <>
      {svgs.map(({ id, svg }) => (
        <div key={id} dangerouslySetInnerHTML={{ __html: svg }} />
      ))}
    </>
  )
}

```

## Error Handling and SSR Considerations

When integrating Mermaid into a React component, consider these edge cases derived from the source implementation:

**Unique ID Generation**: Always use `useId()` or a reliable counter to prevent ID collisions when multiple instances render simultaneously.

**Server-Side Rendering Guard**: Mermaid requires the `window` object and DOM APIs available only in browsers. Wrap initialization and render calls with `if (typeof window !== 'undefined')` checks, or use dynamic imports with `ssr: false` in Next.js.

**Error Boundaries**: The `mermaid.render()` Promise may reject on syntax errors or when parsing invalid diagram definitions. Always implement `.catch()` handlers to prevent unhandled Promise rejections and display fallback UI.

**Cleanup on Unmount**: As shown in the examples, use a `cancelled` boolean flag to prevent calling `setState` after component unmounting, which would trigger React warnings.

## Key Source Files in the Mermaid Repository

Understanding these implementation files helps debug integration issues:

| File | Purpose |
|------|---------|
| [`src/mermaidAPI.js`](https://github.com/mermaid-js/mermaid/blob/main/src/mermaidAPI.js) | Contains the core `render()` method that returns a Promise |
| [`src/initialize.js`](https://github.com/mermaid-js/mermaid/blob/main/src/initialize.js) | Implements `mermaid.initialize()` for global configuration |
| [`src/diagramAPI.js`](https://github.com/mermaid-js/mermaid/blob/main/src/diagramAPI.js) | Handles diagram parsing and temporary DOM container creation |
| [`src/index.js`](https://github.com/mermaid-js/mermaid/blob/main/src/index.js) | Entry point exporting the public API |
| [`src/defaultConfig.js`](https://github.com/mermaid-js/mermaid/blob/main/src/defaultConfig.js) | Default theme and rendering options |

## Summary

- **Initialize once**: Call `mermaid.initialize()` at the module level or inside a `useEffect` with an empty dependency array
- **Handle async rendering**: Use `mermaid.render()` inside `useEffect` to generate SVG strings asynchronously
- **Prevent memory leaks**: Implement cleanup flags to ignore Promise results after component unmount
- **Inject safely**: Use `dangerouslySetInnerHTML` to render the resolved SVG markup
- **Guard for SSR**: Ensure Mermaid code only executes in browser environments with `typeof window !== 'undefined'` checks

## Frequently Asked Questions

### How do I prevent memory leaks when using mermaid.render() in React?

Implement a `cancelled` flag inside your `useEffect` hook. Set the flag to `true` in the cleanup function returned by `useEffect`, and check this flag before calling `setState` in your Promise `.then()` handler. This prevents state updates on unmounted components.

### Can I use Mermaid with Next.js or other SSR frameworks?

Mermaid requires browser-only APIs like `window` and `document`. For Next.js, use dynamic imports with `ssr: false` or check `typeof window !== 'undefined'` before importing or calling Mermaid functions. Alternatively, use the `next/dynamic` import to load the component only on the client side.

### What does the mermaid.render() Promise return?

The Promise resolves to an object containing `{ svg, bindFunctions, bindListeners, errors }`. The `svg` property contains the generated markup as a string. The `errors` array contains any parsing warnings, while `bindFunctions` and `bindListeners` provide callbacks for attaching interactivity to diagram elements.

### How do I update a diagram when the definition changes?

Include the diagram definition string in the `useEffect` dependency array. When the definition prop changes, React re-runs the effect, triggering a new `mermaid.render()` call with the updated text. Ensure you also include the unique `id` in dependencies to maintain consistency between render cycles.