Skip to content

Add mermaid support - #13741

Open
ericwindmill wants to merge 5 commits into
mainfrom
add-mermaid-support
Open

Add mermaid support#13741
ericwindmill wants to merge 5 commits into
mainfrom
add-mermaid-support

Conversation

@ericwindmill

Copy link
Copy Markdown
Contributor

Description of what this PR is changing or adding, and why:

Adds Mermaid diagram support. "Yeehaw" for code and version control instead of saving diagrams as images.

Screenshot 2026-08-18 at 2 43 33 PM

Presubmit checklist

  • If you are unwilling, or unable, to sign the CLA, even for a tiny, one-word PR, please file an issue instead of a PR.
  • If this PR is not meant to land until a future stable release, mark it as draft with an explanation.
  • This PR follows the Google Developer Documentation Style Guidelines—for example, it doesn't use i.e. or e.g., and it avoids I and we (first-person pronouns).
  • This PR uses semantic line breaks
    of 80 characters or fewer.

one --> two
three --> two
two --> c2
``` No newline at end of file

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this for demo purposes. It needs to be removed before this PR lands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for rendering Mermaid diagrams from Markdown code blocks, introducing a custom Markdown block syntax, a node processor, and a client-side MermaidViewer component that dynamically loads the Mermaid library and handles theme updates. Feedback on the implementation highlights a security risk with using securityLevel: 'loose' (XSS), a bug where the diagram does not re-render when its content changes due to a missing didUpdateComponent implementation, an optimization opportunity to cache the imported module, and a potential CSP violation caused by using eval for dynamic imports.

Comment thread packages/site_shared/lib/components/common/client/mermaid_diagram.dart Outdated
Comment thread packages/site_shared/lib/components/common/client/mermaid_diagram.dart Outdated
Comment thread packages/site_shared/lib/components/common/client/mermaid_diagram.dart Outdated
@ericwindmill

Copy link
Copy Markdown
Contributor Author

I'm pretty far out of my element here using js interop and Jaspr, two things I'm only vaguely familiar with. I'd appreciate a thorough review @parlough !

@flutter-website-bot

flutter-website-bot commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Staged preview of the updated docs.flutter.dev site (updated for commit ecd987c):

https://flutter-docs-prod--docs-pr13741-add-mermaid-support-ve3ntyr2.web.app

@flutter-website-bot

flutter-website-bot commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Staged preview of the updated flutter.dev site (updated for commit ecd987c):

https://flutter-dev-230821--www-pr13741-add-mermaid-support-fzptfisf.web.app

.node path {
stroke-width: 1.5px;
fill: var(--site-secondaryContainer-bgColor) !important;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update these base styles to match our themes once I know whether this entire approach is reasonable.

@schultek

schultek commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

As an alternative approach instead of using mermaid.js, we could use https://github.com/orestesgaolin/mermaid/tree/main/packages/mermaid_core to render the diagrams to SVGs at serve/build time.

This is the demo https://roszkowski.dev/mermaid/

Seems like this is not published yet, but if we were to use it maybe we can convince @orestesgaolin to publish it :)

@ericwindmill

Copy link
Copy Markdown
Contributor Author

As an alternative approach instead of using mermaid.js, we could use https://github.com/orestesgaolin/mermaid/tree/main/packages/mermaid_core to render the diagrams to SVGs at serve/build time.

This is the demo https://roszkowski.dev/mermaid/

Seems like this is not published yet, but if we were to use it maybe we can convince @orestesgaolin to publish it :)

I would much rather use this, I'll try it out

@orestesgaolin

Copy link
Copy Markdown
Contributor

Would you like me to publish mermaid to pub.dev? For now I only published katex https://pub.dev/packages/katex

With mermaid I found that it sometimes does not well represent elk layouts and there are slight differences in rendering
screenshot_20260819170012@2x

@ericwindmill

Copy link
Copy Markdown
Contributor Author

Would you like me to publish mermaid to pub.dev? For now I only published katex https://pub.dev/packages/katex

With mermaid I found that it sometimes does not well represent elk layouts and there are slight differences in rendering

I'm not concerned with those small rendering differences. I have noticed one bug, the arrow label renders in the wrong spot when the flowchart is LR oriented. It works correctly when the orientation is TD

Screenshot 2026-08-19 at 8 13 44 AM

If you plan on maintaining this library, we'd likely want to use it over the JSInterop solution (and we can find a way to contribute and help out). But if you don't plan on maintaining, thats okay, no pressure.

@parlough parlough left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for exploring this @ericwindmill! It's exciting. Looks pretty good already, just some questions and comments, primarily about if we can move the rendering to the build?

mermaid_core:
git:
url: https://github.com/orestesgaolin/mermaid.git
ref: round3-fixes-and-packaging

@parlough parlough Aug 20, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason you're relying on this branch over the main branch? Seems like main contains additional updates.

If we're going to use it as a git dependency for now, pin it to a specific commit (like ddb951169592bf089518ba19dbf3bf7ffa8d3c35 from the current main branch).

Comment on lines +57 to +65
```markdown
```mermaid
flowchart LR
A[Start] --> B(Process)
B --> C{Decision}
C -->|Yes| D[Done]
C -->|No| B
```
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```markdown
```mermaid
flowchart LR
A[Start] --> B(Process)
B --> C{Decision}
C -->|Yes| D[Done]
C -->|No| B
```
```
````markdown
```mermaid
flowchart LR
A[Start] --> B(Process)
B --> C{Decision}
C -->|Yes| D[Done]
C -->|No| B
```
````

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want support to be fully enabled on the marketing (www) site where these styles are added, the processor needs to be to be registered as an extension in sites/www/lib/main.server.dart.

```
```

### Styling Mermaid diagrams

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Styling Mermaid diagrams
### Style Mermaid diagrams

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add license headers to these Dart files.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using this as a client dependency that listens for theme changes, can this instead be a server component that renders both versions up front and switches between them with css? That way we can drop the complicated theming logic, avoid shipping the renderer to the client, and improve page load time.

I imagine the component implementation could look something like this:

/// Renders a Mermaid diagram as server-generated SVG.
///
/// Both light and dark variants are included in the page
/// so that CSS can show the variant matching the site's current theme.
final class MermaidDiagram extends StatelessComponent {
  const MermaidDiagram({
    required this.diagram,
    super.key,
  });

  /// The Mermaid diagram definition to render.
  final String diagram;

  @override
  Component build(BuildContext context) {
    // Render both theme variants on the server.
    final lightSvg = _renderDiagram(theme: .defaultTheme);
    final darkSvg = _renderDiagram(theme: .darkTheme);

    return div(
      classes: 'mermaid-container',
      [
        if (lightSvg != null && darkSvg != null) ...[
          div(classes: 'mermaid-theme mermaid-theme-light', [
            RawText(lightSvg),
          ]),
          div(classes: 'mermaid-theme mermaid-theme-dark', [RawText(darkSvg)]),
        ] else
          // If rendering fails,
          // preserve the source in a fallback `<pre>` element.
          pre(
            classes: 'mermaid',
            attributes: {'data-source': diagram},
            [.text(diagram)],
          ),
      ],
    );
  }

  /// Renders [diagram] as SVG using the specified [theme].
  String? _renderDiagram({required MermaidTheme theme}) {
    try {
      // Server rendering doesn't have browser text metrics available, so use
      // the library's deterministic approximation when laying out labels.
      final mermaid = Mermaid(
        measurer: const ApproximateTextMeasurer(),
        theme: theme,
      );
      final scene = mermaid.render(diagram);
      return renderSceneToSvg(scene);
    } catch (error) {
      if (kDebugMode) {
        print('Failed to render Mermaid diagram: $error');
      }
      return null;
    }
  }
}

And the styles could then hide the other depending on the theme. Something like this:

.mermaid-container {
  // ...

  .mermaid-theme-dark {
    display: none;
  }

  @at-root body.dark-mode & {
    .mermaid-theme-light {
      display: none;
    }

    .mermaid-theme-dark {
      display: block;
    }
  }

  // ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants