From 36b749c682f53c895c4883f5c19de972e0f4abfc Mon Sep 17 00:00:00 2001 From: Jan Ulrichts Date: Sat, 15 Aug 2026 14:07:17 +0200 Subject: [PATCH 1/5] Added end-to-end flowchart tests with subgraph styling. --- .../FlowchartTests.cs | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/tests/Mermaid.Flowcharts.Tests/FlowchartTests.cs b/tests/Mermaid.Flowcharts.Tests/FlowchartTests.cs index 0669e91..6e7dace 100644 --- a/tests/Mermaid.Flowcharts.Tests/FlowchartTests.cs +++ b/tests/Mermaid.Flowcharts.Tests/FlowchartTests.cs @@ -409,6 +409,114 @@ class {node3Id},{node4Id} customStyle2 Assert.Equal(expected, actual); } + [Fact] + public void Flowchart_WhenOneSubgraphOneStyle_ToMermaidString() + { + // Arrange + Flowchart flowchart = Flowchart.Create(); + string subgraphId = Guid.NewGuid().ToString(); + string subgraphTitle = Guid.NewGuid().ToString(); + StyleClass subgraphStyleClass = new(Fill: new Fill(Color.FromHex("#ff9966"))); + NodeStyle subgraphStyle = new("customStyle", subgraphStyleClass); + Subgraph subgraph = Subgraph.Create(subgraphId, subgraphTitle, nodeStyle: subgraphStyle); + flowchart.AddNode(subgraph); + string expected = + $""" + flowchart TD + + subgraph {subgraphId} ["{subgraphTitle}"] + end + + classDef customStyle fill:#ff9966 + class {subgraphId} customStyle + + """; + + // Act + string actual = flowchart.ToMermaidString(0, " "); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Flowchart_WhenNestedSubgraphStyled_ToMermaidString() + { + // Arrange + Flowchart flowchart = Flowchart.Create(); + string outerId = Guid.NewGuid().ToString(); + string outerTitle = Guid.NewGuid().ToString(); + Subgraph outer = Subgraph.Create(outerId, outerTitle); + + string innerId = Guid.NewGuid().ToString(); + string innerTitle = Guid.NewGuid().ToString(); + StyleClass innerStyleClass = new(Fill: new Fill(Color.FromHex("#9966ff"))); + NodeStyle innerStyle = new("customStyle", innerStyleClass); + Subgraph inner = Subgraph.Create(innerId, innerTitle, nodeStyle: innerStyle); + + outer.AddNode(inner); + flowchart.AddNode(outer); + string expected = + $""" + flowchart TD + + subgraph {outerId} ["{outerTitle}"] + + subgraph {innerId} ["{innerTitle}"] + end + end + + classDef customStyle fill:#9966ff + class {innerId} customStyle + + """; + + // Act + string actual = flowchart.ToMermaidString(0, " "); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Flowchart_WhenNodeAndSubgraphShareStyle_ToMermaidString() + { + // Arrange + Flowchart flowchart = Flowchart.Create(); + StyleClass sharedStyleClass = new(Fill: new Fill(Color.FromHex("#ff9966"))); + NodeStyle sharedStyle = new("customStyle", sharedStyleClass); + + string nodeId = Guid.NewGuid().ToString(); + string nodeText = Guid.NewGuid().ToString(); + Node node = Node.Create(nodeId, nodeText, nodeStyle: sharedStyle); + + string subgraphId = Guid.NewGuid().ToString(); + string subgraphTitle = Guid.NewGuid().ToString(); + Subgraph subgraph = Subgraph.Create(subgraphId, subgraphTitle, nodeStyle: sharedStyle); + + flowchart + .AddNode(node) + .AddNode(subgraph); + string expected = + $""" + flowchart TD + {nodeId}["{nodeText}"] + + subgraph {subgraphId} ["{subgraphTitle}"] + end + + classDef customStyle fill:#ff9966 + class {nodeId},{subgraphId} customStyle + + """; + + // Act + string actual = flowchart.ToMermaidString(0, " "); + + // Assert + Assert.Equal(expected, actual); + } + [Fact] public void Flowchart_WhenOneLinkOneStyle_ToMermaidString() { From 45ac1235ab72efaa4848b93cf5f85c7c19421626 Mon Sep 17 00:00:00 2001 From: Jan Ulrichts Date: Sat, 15 Aug 2026 14:07:31 +0200 Subject: [PATCH 2/5] Added node style property to INode. --- src/Mermaid.Flowcharts/Nodes/INode.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mermaid.Flowcharts/Nodes/INode.cs b/src/Mermaid.Flowcharts/Nodes/INode.cs index c4615a8..f18d937 100644 --- a/src/Mermaid.Flowcharts/Nodes/INode.cs +++ b/src/Mermaid.Flowcharts/Nodes/INode.cs @@ -3,6 +3,7 @@ namespace Mermaid.Flowcharts.Nodes; public interface INode : IMermaidPrintable { public NodeIdentifier Id { get; } + public NodeStyle? NodeStyle { get; } } public interface INode : INode, IEquatable From a1e3ca67de7cbc3c48825a30ad7bb4be41d3db51 Mon Sep 17 00:00:00 2001 From: Jan Ulrichts Date: Sat, 15 Aug 2026 14:07:51 +0200 Subject: [PATCH 3/5] Implemented node style property and updated factory methods on Subgraph. --- src/Mermaid.Flowcharts/Subgraphs/Subgraph.cs | 28 +++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Mermaid.Flowcharts/Subgraphs/Subgraph.cs b/src/Mermaid.Flowcharts/Subgraphs/Subgraph.cs index 9ffe4e9..d62c8f7 100644 --- a/src/Mermaid.Flowcharts/Subgraphs/Subgraph.cs +++ b/src/Mermaid.Flowcharts/Subgraphs/Subgraph.cs @@ -15,38 +15,40 @@ public record Subgraph : INode public NodeIdentifier Id { get; } public INodeText Title { get; } public SubgraphDirection? Direction { get; } + public NodeStyle? NodeStyle { get; } public IEnumerable Nodes => _nodes.OfType(); public IEnumerable Subgraphs => _nodes.OfType(); public IEnumerable Links => _links.AsReadOnly(); - private Subgraph(NodeIdentifier id, INodeText title, SubgraphDirection? direction = null) + private Subgraph(NodeIdentifier id, INodeText title, SubgraphDirection? direction = null, NodeStyle? nodeStyle = null) { Id = id; Title = title; Direction = direction; + NodeStyle = nodeStyle; } - public static Subgraph CreateNew(string title, SubgraphDirection? direction = null) + public static Subgraph CreateNew(string title, SubgraphDirection? direction = null, NodeStyle? nodeStyle = null) where TNodeText : INodeText - => new(NodeIdentifier.Create(), TNodeText.FromString(title), direction); + => new(NodeIdentifier.Create(), TNodeText.FromString(title), direction, nodeStyle); - public static Subgraph Create(string identifier, string title, SubgraphDirection? direction = null) + public static Subgraph Create(string identifier, string title, SubgraphDirection? direction = null, NodeStyle? nodeStyle = null) where TNodeText : INodeText - => new(NodeIdentifier.FromString(identifier), TNodeText.FromString(title), direction); + => new(NodeIdentifier.FromString(identifier), TNodeText.FromString(title), direction, nodeStyle); - public static Subgraph CreateNew(TNodeText title, SubgraphDirection? direction = null) + public static Subgraph CreateNew(TNodeText title, SubgraphDirection? direction = null, NodeStyle? nodeStyle = null) where TNodeText : INodeText - => new(NodeIdentifier.Create(), title, direction); + => new(NodeIdentifier.Create(), title, direction, nodeStyle); - public static Subgraph Create(string identifier, TNodeText title, SubgraphDirection? direction = null) + public static Subgraph Create(string identifier, TNodeText title, SubgraphDirection? direction = null, NodeStyle? nodeStyle = null) where TNodeText : INodeText - => new(NodeIdentifier.FromString(identifier), title, direction); + => new(NodeIdentifier.FromString(identifier), title, direction, nodeStyle); - public static Subgraph CreateNew(string title, SubgraphDirection? direction = null) - => CreateNew(title, direction); + public static Subgraph CreateNew(string title, SubgraphDirection? direction = null, NodeStyle? nodeStyle = null) + => CreateNew(title, direction, nodeStyle); - public static Subgraph Create(string identifier, string title, SubgraphDirection? direction = null) - => Create(identifier, title, direction); + public static Subgraph Create(string identifier, string title, SubgraphDirection? direction = null, NodeStyle? nodeStyle = null) + => Create(identifier, title, direction, nodeStyle); public Subgraph AddNode(INode node) { From 3fc42408ca147b72eb475bd212f4edc0d5f1a9ac Mon Sep 17 00:00:00 2001 From: Jan Ulrichts Date: Sat, 15 Aug 2026 14:08:19 +0200 Subject: [PATCH 4/5] Included subgraph node children in Flowchart node styling logic. --- src/Mermaid.Flowcharts/Flowchart.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mermaid.Flowcharts/Flowchart.cs b/src/Mermaid.Flowcharts/Flowchart.cs index 1f24f60..b7176a8 100644 --- a/src/Mermaid.Flowcharts/Flowchart.cs +++ b/src/Mermaid.Flowcharts/Flowchart.cs @@ -101,9 +101,9 @@ internal string ToMermaidStringWithOrderedLinks(int indentations, string indenta flowchartStringBuilder.AppendLine(link.ToMermaidString(indentations + 1, indentationText)); } - // Group all node styles across flowchart and all subgraphs recursively together + // Group all node and subgraph styles across flowchart and all subgraphs recursively together Dictionary> distinctNodeStyles = []; - foreach (Node node in AllNodes) + foreach (INode node in AllNodeChildren) { if (node.NodeStyle is null) { From 0db19ea6559c4497cc9cc25676810f43cbd331d2 Mon Sep 17 00:00:00 2001 From: Jan Ulrichts Date: Sat, 15 Aug 2026 14:11:27 +0200 Subject: [PATCH 5/5] Added README test and updated README to add a subgraph styling example. --- README.md | 47 ++++++++++++++++++- tests/Mermaid.Flowcharts.Tests/ReadmeTests.cs | 39 +++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f799a8..7da3700 100644 --- a/README.md +++ b/README.md @@ -339,7 +339,7 @@ This type wraps some common style attributes, such as: #### Styling nodes -In Mermaid, nodes can be through a style class definitions, which show up as `classDef` inside the flowchart. +In Mermaid, nodes can be styled using a style class definition, which show up as `classDef` inside the flowchart. To do this, you must create a `NodeStyle` with a given name and a `StyleClass` and use that node style when creating a node. If you create multiple nodes using the same node style, they will be grouped together automatically when applying the style class. @@ -384,6 +384,51 @@ flowchart TD ``` +#### Styling subgraphs + +Subgraphs are nodes too, so they can be styled the same way with a `NodeStyle`. +Subgraphs and nodes can share the same node style, in which case they are grouped together automatically, just like nodes sharing a style. + +```cs +using Mermaid.Flowcharts; +using Mermaid.Flowcharts.Nodes; +using Mermaid.Flowcharts.Subgraphs; + +// Create a new flowchart +Flowchart flowchart = Flowchart.Create("Styling subgraphs"); + +// Define a style class +StyleClass subgraphStyleClass = new(Fill: new Fill(Color.FromHex("#9966ff"))); + +// Create a named node style +NodeStyle subgraphStyle = new("customStyle", subgraphStyleClass); + +// Create a subgraph with the node style +Subgraph subgraph = Subgraph.Create("sg", "Subgraph", nodeStyle: subgraphStyle); + +// Add the subgraph to the flowchart +flowchart.AddNode(subgraph); + +// Generate the Mermaid output +string mermaid = flowchart.ToMermaidString(); +``` + +Will generate the following Mermaid output: + +```mermaid +--- +title: "Styling subgraphs" +--- +flowchart TD + + subgraph sg ["Subgraph"] + end + + classDef customStyle fill:#9966ff + class sg customStyle + +``` + #### Styling links Styling links does not require a separate class, you directly apply a `StyleClass` to them. diff --git a/tests/Mermaid.Flowcharts.Tests/ReadmeTests.cs b/tests/Mermaid.Flowcharts.Tests/ReadmeTests.cs index c0ef09b..1020594 100644 --- a/tests/Mermaid.Flowcharts.Tests/ReadmeTests.cs +++ b/tests/Mermaid.Flowcharts.Tests/ReadmeTests.cs @@ -273,6 +273,45 @@ class a,b customStyle Assert.Equal(expected, mermaid); } + [Fact] + public void StylingSubgraphs() + { + // Create a new flowchart + Flowchart flowchart = Flowchart.Create("Styling subgraphs"); + + // Define a style class + StyleClass subgraphStyleClass = new(Fill: new Fill(Color.FromHex("#9966ff"))); + + // Create a named node style + NodeStyle subgraphStyle = new("customStyle", subgraphStyleClass); + + // Create a subgraph with the node style + Subgraph subgraph = Subgraph.Create("sg", "Subgraph", nodeStyle: subgraphStyle); + + // Add the subgraph to the flowchart + flowchart.AddNode(subgraph); + + // Generate the Mermaid output + string mermaid = flowchart.ToMermaidString(); + string expected = + """ + --- + title: "Styling subgraphs" + --- + flowchart TD + + subgraph sg ["Subgraph"] + end + + classDef customStyle fill:#9966ff + class sg customStyle + + """; + + // Assert + Assert.Equal(expected, mermaid); + } + [Fact] public void StylingLinks() {