Card node layout
Card node layout is for nodes that need to read like compact operational records instead of plain device glyphs.
The node is still a roundRectangle. The nested nodeLayout object only
changes the internal arrangement: icon box on the left, title and subtitle on
the right. Badges and status markers stay node-level controls, so a card can
keep a TurboFlow-style badge on the top-right shell while its icon cell renders
either a glyph or an inline SVG. Use the badge size keys when the compact
defaults are too small for the card body.
Use this pattern for service maps, application dependencies, Kubernetes objects, or operations views where every node needs a name plus one short piece of metadata.
Expected Result
Nested nodeLayout makes round-rectangle nodes read like compact service cards.
Try It
- Copy the two YAML tabs into your own project.
- In the
noderule in stylesheet.yaml, setnodeLayout.content.alignto"center". - Reload. The card title and subtitle align centrally in their content cell; the icon remains separate.
- Restore the original settings and reload to compare with the starting view.
version: "0.2"
graph:
id: node-card-layout
layers:
- id: services
labels:
name: Services
nodes:
- id: api
labels:
role: frontend
state: healthy
name: API gateway
data:
subtitle: ingress / active
badge: "4"
layers: [ services ]
position:
- 100
- 150
- id: orders
labels:
role: service
state: busy
name: Orders service
data:
subtitle: checkout path
badge: "12"
layers: [ services ]
position:
- 410
- 150
- id: database
labels:
role: database
state: healthy
name: Orders database
data:
subtitle: primary / eu-west
badge: "1"
layers: [ services ]
position:
- 720
- 150
links:
- id: api-orders
source: api
target: orders
layers: [ services ]
labels:
name: REST
- id: orders-database
source: orders
target: database
layers: [ services ]
labels:
name: SQL
version: "0.2"
layout:
mode: manual
width: 760
height: 300
icons:
router.nokia:
glyph: "N"
alt: Nokia router
svg: |
<svg
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="enable-background:new 0 0 120 120;"
viewBox="0 0 120 120"
y="0px"
x="0px"
id="Layer_1"
version="1.1"
width="120px"
height="120px"
fill="none"
>
<style type="text/css">
.st0 { fill: #26313c; }
.st1 { fill: none; stroke: #FFFFFF; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 10; }
</style>
<rect height="120" width="120" class="st0" />
<g>
<g>
<path d="M71.7,19.7V48h28" class="st1" />
<path d="M91.2,38.5l7.5,7.6c1.3,1.3,1.3,3.1,0,4.3L91.1,58" class="st1" />
</g>
<g>
<path d="M20,47.8h28.4v-28" class="st1" />
<path d="M38.8,28.3l7.6-7.5c1.3-1.3,3.1-1.3,4.3,0l7.7,7.6" class="st1" />
</g>
<g>
<path d="M48,100.3V72H20" class="st1" />
<path d="M28.5,81.5L21,73.9c-1.3-1.3-1.3-3.1,0-4.3l7.6-7.7" class="st1" />
</g>
<g>
<path d="M100,71.9H71.6v28" class="st1" />
<path d="M81.2,91.4l-7.6,7.5c-1.3,1.3-3.1,1.3-4.3,0l-7.7-7.6" class="st1" />
</g>
</g>
</svg>
service:
glyph: SVC
fill: "#26313c"
stroke: "#a3b0bd"
database:
glyph: DB
fill: "#26313c"
stroke: "#a3b0bd"
labelFields:
- labels.name
stylesheet:
- selector: node
style:
shape: roundRectangle
width: 240
height: 64
backgroundColor: "var(--topoviewer-panel-bg)"
borderColor: "var(--topoviewer-edge-default)"
borderWidth: 2
color: "#e2e8f0"
labelColor: "var(--topoviewer-fg-strong)"
metaColor: "var(--topoviewer-fg-muted)"
iconPadding: 6
badgeColor: "var(--topoviewer-fg-strong)"
badgeBackgroundColor: "color-mix(in srgb, var(--topoviewer-info) 12%,
var(--topoviewer-panel-bg))"
badgeBorderColor: "var(--topoviewer-info)"
badgeBorderWidth: 2
badgeFontSize: 11
badgeFontWeight: 900
badgeMinWidth: 22
badgeMinHeight: 22
badgePadding: 3
badgeOffset: 11
badgePosition: topRight
statusPlacement: topRight
statusSize: 16
nodeLayout:
type: card
direction: horizontal
icon:
placement: left
width: 44
height: 44
content:
align: left
titleField: name
subtitleField: data.subtitle
labelFontSize: 14
labelFontWeight: 600
metaFontSize: 12
iconColor: var(--topoviewer-fg-strong)
- selector: node[labels.role = "frontend"]
style:
icon: router.nokia
borderColor: "var(--topoviewer-accent)"
badgeLabel: "4"
- selector: node[labels.role = "service"]
style:
icon: service
borderColor: "var(--topoviewer-info)"
badgeLabel: "12"
- selector: node[labels.role = "database"]
style:
icon: database
borderColor: "#8b78b8"
badgeLabel: "1"
- selector: node[labels.state = "healthy"]
style:
statusColor: "var(--topoviewer-success)"
- selector: node[labels.state = "busy"]
style:
statusColor: "var(--topoviewer-warning)"
outlineColor: "var(--topoviewer-warning)"
outlineWidth: 2
outlineOpacity: 0.45
- selector: link
style:
curveStyle: bezier
lineColor: "var(--topoviewer-edge-default)"
lineWidth: 3
targetArrowShape: triangle
targetArrowColor: "var(--topoviewer-accent)"
labelColor: "var(--topoviewer-fg-strong)"
textBackgroundColor: "color-mix(in srgb, var(--topoviewer-accent) 12%,
var(--topoviewer-panel-bg))"
labelFontSize: 12
labelFontWeight: 600