Elements that can be styled
Here is a simplified list of some of the element types, especially those that have built-in "default" styles.
This will need to be expanded to show the proper hierarchy, and which elements are supported for styling.
| Element | in which diagram type ? | Hardcoded styles used |
|---|---|---|
Actor |
SequenceDiagram |
|
Stereotype of Actor |
SequenceDiagram |
|
Boundary |
SequenceDiagram |
|
Stereotype of Boundary |
SequenceDiagram |
|
messages |
SequenceDiagram |
|
Actor |
ComponentDiagram |
|
Stereotype of Actor |
ComponentDiagram |
|
Boundary |
ComponentDiagram |
|
Stereotype of Boundary |
ComponentDiagram |
|
Title |
SequenceDiagram |
|
Title |
ComponentDiagram |
|
Title |
ClassDiagram |
|
Footer |
SequenceDiagram |
|
Footer |
ComponentDiagram |
|
Footer |
ClassDiagram |
|
(We use classDiagram because later we will need class which will only apply to actual UML class entities.)
Note that Title, Footer, and Caption are not real UML elements, and will be dealt with differently.
Targeting Specific Diagram Element
We have to define how we apply style so a specific element of a UML diagram (for example, only for participant Bob or for a specific message between Alice and Bob).
To me, some style can be defined, but the style definition should not mention the specific element (otherwise it means that the style definition is specific to one diagram).
I know that this is different from what CSS allows.
Option 3
In Option 3 proposal, styles cannot inherit from each other. However, each element can have several styles (like in CSS) and there are a mecanism based on priority to solve multiple inheritance issues in property value.
Let’s first focus on some elements (actor, boundary which can be used in several diagram type).
If you want use blue color for text everywhere:
Internally, there is a "plantuml.skin" file stored in the plantuml.jar library that store all settings (so no more hardcoded value in the code). The previous example only overrides the fontcolor of the root style.
So now, imagine that you want all UML elements (so not for title, footer…) in green:
The order of declaration is important: since "element" is defined after "root", the priority of green setting is higher than the priority of blue setting.
Now, you want also all actor printed in red:
@startuml
skinparam useBetaStyle true
title Styling example
actor Alice
Alice -> Bob : hello
@enduml@startuml
skinparam useBetaStyle true
title Styling example
actor Alice
Alice -> Bob : hello
@endumlNow, you want also sequence diagrams printed in purple:
@startuml
skinparam useBetaStyle true
title Styling example
' In that case, actor from sequence diagrams will be in purple, because purple is defined after red.
actor Alice
Alice -> Bob : hello
@enduml@startuml
skinparam useBetaStyle true
title Styling example
' In that case, actor from sequence diagrams will be in purple, because purple is defined after red.
actor Alice
Alice -> Bob : hello
@enduml@startuml
skinparam useBetaStyle true
title Styling example
actor Alice
Alice -> Bob : hello
@endumlChanging the order definition will only change the color of actor in sequence diagram:
@startuml
skinparam useBetaStyle true
title Styling example
' In that case, actor from sequence diagrams will be in red, because red is defined after purple.
actor Alice
Alice -> Bob : hello
@enduml@startuml
skinparam useBetaStyle true
title Styling example
' In that case, actor from sequence diagrams will be in red, because red is defined after purple.
actor Alice
Alice -> Bob : hello
@endumlFinally, there is also a way to change a setting for a element which have two or more precise styles:
@startuml
skinparam useBetaStyle true
title Styling example
' In that case, only actor from sequence diagram are printed in blue.
' Actors in other diagram and other sequence element are unchanged.
actor Alice
Alice -> Bob : hello
@enduml@startuml
skinparam useBetaStyle true
title Styling example
' In that case, only actor from sequence diagram are printed in blue.
' Actors in other diagram and other sequence element are unchanged.
actor Alice
Alice -> Bob : hello
@endumlYou can also defined your own style. In that case, they could be used when needed with the stererotype notation :
@startuml
<style>
actor {
Padding 10
}
MorePadding {
Image <&check>
ImagePosition BeforeText
' or AfterText
' <img:> convention also supported
fontSize 24
Size 32
Padding 20
}
message {
fontSize 24
}
SmallFont {
fontSize 10
}
</style>
participant Bob
actor Alice <<MorePadding>>
'In that case Alice with use the style "root, element, sequence, actor, MorePadding"
participant Sally
Bob->Alice: Hello
Alice->Sally: Also Hello! <<SmallFont>>
' This is new: you can use stereotype on message
@enduml
Here is another example:
@startuml
participant Bob
actor Alice
participant Sally
Bob->Alice: Hello <>
Alice->Sally: Also Hello!
@enduml @startuml
participant Bob
actor Alice
participant Sally
Bob->Alice: Hello <>
Alice->Sally: Also Hello!
@enduml Unfortunately here, you have to manually set <<BobAndAliceMessage>>.
Varying style
There is another limitation of current skinparam features: the parameter are defined once along the diagram and you cannot change values across the diagram.
The idea here is to allow a style to be different in some context (for example a package) or to change over the execution of the diagram.
For example:
@startuml
skinparam useBetaStyle true
style message {
FontColor blue
}
Alice -> Bob : this is printed in blue
style message {
FontColor red
}
Alice -> Bob : this is printed in red
@endumlOr in some usecase diagram:
@startuml
style actor {
FontColor blue
}
'foo1 is printed in blue
actor foo1
package myPackage {
' Style modification in this package are local
style actor {
FontColor red
}
'foo2 is printed in red
actor foo2
}
' We left the package, so we're back to previous style definition
'foo3 is also printed in blue
actor foo3
@enduml
Mixing style and stereotype
Styles and stereotypes are going to be very close notions.
Stereotypes could be defined as style to change colors, font… The only difference is that a stereotype is printed on diagrams using standard UML notation while a style is never printed on diagrams. So styles and stereotypes affect rendering in the same way.
For example, you can have:
@startuml
skinparam useBetaStyle true
stereotype foo1 {
FontColor green
}
style dummy1 {
FontColor red
}
participant Alice <>
participant Bob <>
@enduml Alice is going to be printed in green and Bob in red. However, <<foo1>> is going to be printed on the diagram while you won’t see any dummy1 string.
Now, since stereotype are printed, you can change stereotype colors using a style named stereotype
@startuml
skinparam useBetaStyle true
stereotype foo1 {
FontColor red
}
style stereotype {
FontColor green
}
participant Bob <>
@enduml So Bob is going to be printed in red and <<dummy1>> is going to be printed in green.
Now you can also do complex stuff:
@startuml
skinparam useBetaStyle true
style dummy1 {
FontColor purple
FontStyle bold
BackgroundColor white
}
stereotype foo3 {
FontColor blue
FontStyle bold
}
style stereotype {
FontColor green
FontSize 8
}
style stereotype+foo3 {
FontSize 24
FontColor red
}
participant Bob <>
actor Alice <>
actor Charlie <>
actor David <>
@enduml Potential Use Extensions
[KJW]Have style Parameters equivalent to Skin Parameters applied conditionally
!function formatConnection($sequenceArrowThickness, $from, $to, $protocol) <style:sequenceArrowThickness $sequenceArrowThickness> $from<<->>$to : $protocol <style:sequenceArrowThickness 1> !endfunction
<code>box "AWS " #LightBlue
participant "aPlatform" as ap
end box</code>
<code>box "External" #Lightgreen
participant "EXternal API" as extapi participant ""EXternal Service" as exts
end box</code>
<code>formatConnection("2", "ap", "extapi","<< MA-TLS >>")</code>
OR
<code>ap<<→>extapi : <style:sequenceArrowThickness 2> << MA-TLS >></code>
Result is only this sequence line is 2 the rest are the default 1
plantuml.skin file
This is the default file used by PlantUML. Users will be able to modify this file or to create their own foo.skin file.
style root {
FontName SansSerif
HyperLinkColor red
FontColor black
FontSize 14
FontStyle plain
HorizontalAlignment left
RoundCorner 0
DiagonalCorner 0
LineThickness 1.0
LineColor #A80036
BackGroundColor #FEFECE
Shadowing 0.0
}
style stereotype {
FontStyle italic
}
style title {
HorizontalAlignment center
FontSize 14
FontStyle bold
Padding 0
Margin 4
LineColor none
BackGroundColor none
}
style header {
HorizontalAlignment center
FontSize 10
FontColor #888888
}
style footer {
HorizontalAlignment left
FontSize 10
FontColor #888888
}
style legend {
LineColor black
BackGroundColor #DDDDDD
FontSize 14
RoundCorner 15
Padding 6
Margin 8
}
style caption {
HorizontalAlignment center
FontSize 14
Padding 0
Margin 1
LineColor none
BackGroundColor none
}
style element {
Shadowing 4.0
}
style sequenceDiagram {
}
style classDiagram {
}
style activityDiagram {
}
style group {
BackGroundColor none
LineColor black
LineThickness 2.0
FontSize 11
FontStyle bold
}
style groupHeader {
BackGroundColor #EEEEEE
LineColor black
FontSize 13
FontStyle bold
}
style lifeLine {
BackGroundColor none
}
style destroy {
}
style reference {
LineColor red
FontSize 10
FontStyle bold
FontColor blue
BackGroundColor gold
HorizontalAlignment right
}
style box {
BackGroundColor #DDDDDD
FontSize 13
FontStyle bold
}
style separator {
LineColor black
LineThickness 2.0
BackGroundColor #EEEEEE
FontSize 13
FontStyle bold
}
style delay {
FontSize 22
FontStyle italic
}
style participant {
LineThickness 1.5
}
style actor {
LineThickness 2.0
}
style boundary {
}
style control {
}
style entity {
}
style queue {
}
style database {
}
style collections {
}
style swimlane {
}
style diamond {
}
style arrow {
FontSize 13
}
style note {
FontSize 13
BackGroundColor #FBFB77
}
style partition {
}
style circle {
}
debug.skin file
This file is used as an alternative possible skin file for debugging purpose. It is integrated into beta version.
style root {
FontName SansSerif
HyperLinkColor red
FontColor green
FontSize 19
FontStyle plain
HorizontalAlignment left
RoundCorner 15
DiagonalCorner 0
LineColor #3600A8
LineThickness 1.0
BackGroundColor #AAA
Shadowing 0.0
}
style stereotype {
FontColor blue
FontSize 8
FontStyle bold
}
style title {
HorizontalAlignment right
FontSize 24
FontColor blue
}
style header {
HorizontalAlignment center
FontSize 26
FontColor purple
}
style footer {
HorizontalAlignment left
FontSize 28
FontColor red
}
style legend {
FontSize 30
BackGroundColor yellow
Margin 30
Padding 50
}
style caption {
FontSize 32
}
style element {
BackGroundColor #CEFEFE
}
style sequenceDiagram {
}
style classDiagram {
}
style activityDiagram {
}
style group {
LineThickness 3.5
BackGroundColor MistyRose
LineColor DarkOrange
FontSize 12
FontStyle italic
FontColor red
}
style groupHeader {
BackGroundColor tan
LineThickness 0.5
LineColor yellow
FontSize 18
FontStyle bold
FontColor blue
}
style lifeLine {
BackGroundColor gold
}
style destroy {
LineColor red
}
style reference {
LineColor red
FontSize 10
FontStyle bold
FontColor blue
BackGroundColor gold
HorizontalAlignment right
}
style box {
LineThickness 0.1
LineColor FireBrick
BackGroundColor PowderBlue
FontSize 12
FontStyle italic
FontColor Maroon
}
style separator {
LineColor red
BackGroundColor green
FontSize 16
FontStyle bold
FontColor white
}
style delay {
FontSize 22
FontStyle italic
}
style participant {
LineThickness 2.5
}
style actor {
LineThickness 0.5
}
style boundary {
LineThickness 1.5
}
style control {
LineThickness 1.5
}
style entity {
LineThickness 1.5
}
style queue {
LineThickness 1.5
}
style database {
LineThickness 1.5
}
style collections {
LineThickness 1.5
}
style arrow {
FontSize 13
LineColor Lime
}
style note {
BackGroundColor GoldenRod
}
style diamond {
}
style swimlane {
}
style activity {
BackgroundColor #33668E
BorderColor #33668E
FontColor #888
FontName arial
}
style activityDiagram && diamond {
BackgroundColor #dae4f1
BorderColor #33668E
FontColor red
FontName arial
FontSize 5
}
style activityDiagram && arrow {
FontColor gold
FontName arial
FontSize 15
}
style activityDiagram && partition {
LineColor red
FontColor green
RoundCorner 30
}
style activityDiagram && note {
FontColor Blue
LineColor yellow
}
style circle {
BackgroundColor yellow
}
Legacy discussions
We keep here some previous discussions. We do not delete them because they contain some interesting ideas. Maybe we are going to reuse them.
First style proposal
A first idea is to use the same notion as CSS (cascading style sheet). The cascading feature may be useful to avoid duplication in skinparam/style feature. All elements will have one default (predefined) style, which may inherit for another default style. Users will be able either:
-
to create a new style and to apply it to some element
-
to modify any predefined style.
Let’s start by an simple example:
@startuml actor Alice boundary Bob Alice -> Bob : hello @enduml
By default, all elements uses the root style, so you can change the font name of all text of this diagram with:
Let’s say we have the following style hierarchy:
@startuml
title Style hierarchy cascade
skinparam ranksep 30
hide circle
hide empty members
class root
class element extends root
class actor extends element
class boundary extends element
class message extends root
@enduml@startuml
style root {
fontName Arial
}
style element {
fontName Courier
fontColor Red
}
syle actor {
fontSize 14
}
style boundary {
fontColor Blue
}
actor Alice
boundary Bob
Alice -> Bob : hello
@enduml
[RG] — If the format of CSS is followed, the above example could be extended in a similar fashion for targeting specific elements perhaps:
@startuml
style root {
fontName Arial
}
style element {
fontName Courier
fontColor Red
}
style actor.Bob, boundary.Alice {
fontSize 14
}
style message {
fontSize 24
}
style message.Bob:Alice
{
BackgroundColor Black
}
actor Alice
boundary Bob
Alice -> Bob : hello
@enduml
The syntax for selecting the entity could take many forms. I’ve used : for simplicity. Implementing a full descendant selection matching like CSS is more powerful, but also likely more complex, i.e. ancestor > descendant. It seems most scenarios involve two entities at most, so a simple matching pair may be sufficient, with some minor additional flexibility for directional allowances. To continue the example above, it might look like:
@startuml
style message {
fontSize 24
}
style message.Bob:Alice
{
BackgroundColor Black
}
style message.Bob>Alice
{
BackgroundColor Blue
}
actor Alice
boundary Bob
Alice -> Bob : hello
'fontSize 24 && BackgroundColor Black
Bob o-> Alice : hi
'fontSize 24 && BackgroundColor Black && BackgroundColor Blue
'BackgroundColor would resolve as standard cascade to last defined value, "Blue"
'or precedence possibly, i.e. a specific relationship ">" is higher order than
'"any" relationship ":"
@enduml
It would nice to be mindful of some other outstanding requests that would like to see some form of metadata follow through into SVG output, for postprocessing with other tools. For example, I have opened the SVG in Sketch and used a tool to locate elements of a given name or type to make changes, which currently is quite hard. To incorporate that in a basic fashion:
[AR] Agreed on the need for SVG ouput. I propose to use exportedName property for this purpose
@startuml
style message {
styleName "DefaultMessage"
'default value, not required but processed by system if no styleName found? See example below for
'counter argument
fontSize 24
}
style message.Bob:Alice {
styleName "BobAndAliceMessage"
' provided by user. If not provided by user, perhaps system generate in output with basic
' convention like CamelCase to hyphens: Bob-Alice-Message
' But I think it's acceptable to simply state "if user wants a value here, they should supply it"
fontSize 10
}
participant Bob
actor Alice
participant Sally
Bob->Alice: Hello
Alice->Sally: Also Hello!
@enduml
I think the main drawback of doing the selectors in the style section is the dynamic nature of PlantUML, where new entities may be defined on the fly. But in many ways this is no different than HTML/CSS. To take a slightly different tact, focusing on style application happening in the UML itself:
[AR] Here, I don’t like the idea of style targeting individual element of a specific diagram. According to me, it prevent the reuse of some existing style file several diagrams.
@startuml
style actor {
Padding 10
}
style actor {
styleName "MorePadding"
Image <&check>
ImagePosition BeforeText
' or AfterText
' <img:> convention also supported
fontSize 24
Size 32
Padding 20
}
style message {
styleName "DefaultMessage"
fontSize 24
}
style message {
styleName "SmallFont"
fontSize 10
}
participant Bob
actor Alice <style:"MorePadding">
' or actor <style:"MorePadding"> Alice
' or !style "MorePadding"
participant Sally
Bob->Alice: Hello
Alice->Sally: <style:"SmallFont"> Also Hello!
@enduml
It may be a personal choice, but I feel the cleaner the UML markup itself, the better. For example, to prevent having something like a Swimlane title, that must be repeated such as <&check><size:24><c:blue> \nSome\nName. With Macros or Variables this can be easier, but still is another layer of mental abstraction. None of this prevents doing that of course, to keep compatibility as is mentioned.
[AR] agreed on the cleaner the UML markup itseft, the better.
Targeting Specific Diagram types
It is important meet the goal of reusing a "style set", i.e. putting many definitions in one file for many diagram types. The common example of this is a "Design System", so that a common style may be followed across different diagrams.
Following the initial example, a convention could be followed such as:
would result in hierarchy:
@startuml
title Style hierarchy cascade per type Option1
skinparam ranksep 30
hide circle
hide empty members
class root
class message extends root
class element extends root
class actor extends element
class "SequenceDiagram.message" extends message
class "SequenceDiagram.actor" extends actor
@endumlor alternately:
@startuml
title Style hierarchy cascade per type Option2
skinparam ranksep 30
hide circle
hide empty members
class root
class message extends root
class actor extends root
class SequenceDiagram extends root
class SequenceDiagram.message extends SequenceDiagram
class SequenceDiagram.actor extends SequenceDiagram
@endumlIt would seem Option1 makes more sense in an inheritance/parsing sense. Option2 would likely result in challenges in traversing/cascading the styles. I also note that this conflicts with my syntax above for style assignment (reusing the . operator), so perhaps one or the other may need to change if it was difficult to manage. Perhaps: style message.Bob:Alice in SequenceDiagram or style SequenceDiagram.message(Bob:Alice) or even style SequenceDiagram.message.Bob:Alice.
[AR] I fully agree on the need (except for targeting indivual element), and I will propose an Option3.