---
title: "A Diagram Renderer of your own"
description: "A Diagram Renderer turns a diagram's source text into an SVG string, for one or more diagram formats such as Mermaid."
canonical_url: "https://tiptap-docs.lin52025i.qzz.io/diagrams/renderers/custom-diagrams"
---

# A Diagram Renderer of your own

A Diagram Renderer turns a diagram's source text into an SVG string, for one or more diagram formats such as Mermaid.

## Quick start

This Diagram Renderer sends Mermaid source to a rendering service you host:

```ts
import type { DiagramRenderer } from '@tiptap-pro/extension-diagrams'

export function serviceDiagramRenderer(endpoint: string): DiagramRenderer {
  return {
    id: 'mermaid-service',
    label: 'Mermaid (service)',
    formats: ['mermaid'],
    async render({ source, theme, raster }) {
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ source, theme, htmlLabels: !raster }),
      })
      if (!response.ok) throw new Error(`The diagram service answered ${response.status}`)
      const svg = await response.text()
      const root = new DOMParser().parseFromString(svg, 'image/svg+xml').documentElement
      const width = Number.parseFloat(root.getAttribute('width') ?? '') || 600
      const height = Number.parseFloat(root.getAttribute('height') ?? '') || 400
      return { svg, width, height }
    },
  }
}
```

```ts
Diagrams.configure({
  diagramRenderers: [serviceDiagramRenderer('https://diagrams.example.com/mermaid/svg')],
})
```

## Members

| Member    | Type                                         | Description                                                                                                                                                                  |
| --------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`      | `string`                                     | Names the Renderer                                                                                                                                                           |
| `label`   | `string`                                     | Optional. For a menu                                                                                                                                                         |
| `formats` | `readonly FlowDiagramFormat[]`               | The diagram formats it draws                                                                                                                                                 |
| `draws`   | `(source: string) => boolean`                | Optional. Whether it draws this source, such as only some Mermaid kinds. Without it, every source                                                                            |
| `rules`   | `RendererRules`                              | Optional. See [Rules of your Renderer](https://tiptap-docs.lin52025i.qzz.io/diagrams/renderers/custom.md#rules-of-your-renderer)                                             |
| `render`  | `(input) => Promise<{ svg, width, height }>` | Draws the source, described below                                                                                                                                            |
| `editing` | `DiagramEditing`                             | Optional. Finds texts and shapes in its SVG, see [Editing in the diagram](https://tiptap-docs.lin52025i.qzz.io/diagrams/renderers/custom-diagrams.md#editing-in-the-diagram) |

## Which Renderer draws a diagram

The extension picks the first registered Diagram Renderer whose `formats` include the diagram's
format and whose `draws` does not decline the source. Empty source goes to the first Diagram
Renderer of its format, without asking `draws`.

A kind no Renderer draws shows what [`unavailable`](https://tiptap-docs.lin52025i.qzz.io/diagrams/api-reference/options.md#unavailable) returns, with
the reason `'unsupported-kind'`. The source stays in the document. Unlike a chart Renderer, a
declining Diagram Renderer never draws the diagram after all.

### A format of your own

`insertFlowDiagram` and `updateFlowDiagram` accept a format while a registered Diagram Renderer
lists it in `formats`. It needs no other registration.

- **The format's id** has letters, digits, `_` and `-`, up to 64 characters.
- **The source** is stored as it is, up to 1,000,000 characters.
- **A format no registered Diagram Renderer draws** stays in the document unchanged and survives
  every save. The diagram shows what `unavailable` returns.

## What render receives

| Input    | Type                | Description                                                                                                                                                                      |
| -------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `format` | `FlowDiagramFormat` | `mermaid`, `drawio`, `bpmn` or a format of your own, one of the Renderer's `formats`                                                                                             |
| `source` | `string`            | The diagram source text, as the document stores it                                                                                                                               |
| `theme`  | `DiagramTheme`      | Resolved colors and fonts, read from the `--tt-flow-diagram-*` custom properties ([Diagrams](https://tiptap-docs.lin52025i.qzz.io/diagrams/api-reference/selectors.md#diagrams)) |
| `raster` | `boolean`           | `true` when the SVG becomes a PNG, a WebP, a JPEG or an image in Word                                                                                                            |

When `raster` is `true`, write labels as SVG text. The SVG must hold no `foreignObject`, because
the browser does not let a canvas export one.

## What render returns

`render` returns `{ svg, width, height }`. `svg` is a standalone SVG string with a `width` and a
`height`. `width` and `height` are numbers, the size of the drawing in pixels.

## Editing in the diagram

A user can double click a text in a diagram to edit it, and drag a shape to move it. See
[Editing in the diagram](https://tiptap-docs.lin52025i.qzz.io/diagrams/flow-diagrams/editing.md). Only the Renderer knows where texts and
shapes are in its SVG, so it tells the extension through `editing`. Every function of `editing`
receives the SVG that `render` returned, as a string, and the diagram's source.

| Member          | Signature                                         | Without it                                                                      |
| --------------- | ------------------------------------------------- | ------------------------------------------------------------------------------- |
| `labelAt`       | `(svg, point, source) => DiagramLabelHit \| null` | A double click opens nothing                                                    |
| `nodeAt`        | `(svg, point, source) => DiagramNodeHit \| null`  | No shape can be dragged                                                         |
| `movePositions` | `(svg, positions, source) => string \| null`      | No shape can be dragged. Stored offsets are not drawn, but stay in the document |

- **`point`** is in the SVG's own units, through its `viewBox`.
- **`DiagramLabelHit`** is `{ target, label, box }`. `target` names the text in the source, such
  as `{ kind: 'node', id: 'A' }`. The extension writes the new text there.
- **`DiagramNodeHit`** is `{ id, label, box }`. `id` is the shape's id in the source.
- **`movePositions`** returns the SVG with each shape moved by its offset, or `null` when nothing
  moved.
- **Return `null`** for a diagram kind your Renderer does not handle.

A Renderer that draws with mermaid.js can reuse the built-in `editing`:

```ts
import { mermaidDiagramEditing } from '@tiptap-pro/extension-diagrams/mermaid'

const renderer = { id: 'my-mermaid', formats: ['mermaid'], render, editing: mermaidDiagramEditing }
```

## Keeping your web page safe

The editor shows the SVG in an `<img>`, so scripts and outside resources in the SVG never run or
load in your web page.

Never evaluate the source in your web page. Render it on a server or in a sandboxed iframe, as
the built-in Renderers do. A library that only parses text and needs no DOM can draw in a Web
Worker instead, as the [Pele](https://tiptap-docs.lin52025i.qzz.io/diagrams/renderers/pele.md) Renderer does.
