Diagram - Theming
Shared CSS roles, copied shell dimensions and portable authored appearance.
Theme roles control presentation. Authored label colors and symbol paints travel with saved content. A local CSS override does not create a model edit or define the appearance of a portable export.
#Styles
@import '@primeui/diagram-style/style.css';
@import '@primeui/diagram-style/themes/primeone.css';
.review-diagram {
--p-diagram-node-fill: light-dark(#eff6ff, #172554);
--p-diagram-node-stroke: light-dark(#1e40af, #93c5fd);
--p-diagram-selection: light-dark(#1d4ed8, #bfdbfe);
}Put the class on an ancestor of the relevant root and copied controls. Both
presets use these roles and the shared structural stylesheet. The theme entry
defines roles on :root and :host; application overrides follow both imports.
light-dark() follows the applicable color-scheme. Copied PrimeOne controls
also use their PrimeVue theme; application HTML content needs its own styling.
The structural stylesheet loads the bundled Geist variable font. The shared
--p-diagram-font-family role defaults to Geist, ui-sans-serif, system-ui, sans-serif and applies to roots, palettes, copied editors and workspace
dialog/select overlays. Runtime labels without an authored font, notation text,
rulers and tooltips inherit that family. Override the role on the relevant
Diagram scope to use another font. The bundled font includes its SIL Open Font
License in the style package's styles/fonts/OFL.txt.
Loading the browser font does not embed it in exported files. Supply an export font family and a matching approved WOFF2 resource when output needs that face; see Export.
#Diagram roles
These are the roles defined by themes/primeone.css. Light/dark surface fallbacks
apply when the corresponding PrimeOne token is absent.
| CSS variable | Source default / dependency | Used for |
|---|---|---|
--p-diagram-font-family | Geist, ui-sans-serif, system-ui, sans-serif | Diagram content and copied control text |
--p-diagram-editor-surface | --p-content-background; surface 0/900 | Controls and editor surface |
--p-diagram-editor-panel | Editor surface | Panel and utilities surfaces |
--p-diagram-editor-canvas | Surface 50/950; #fafafa/#09090b | Canvas background |
--p-diagram-editor-border | --p-content-border-color; surface 200/700 | Shell and control borders |
--p-diagram-editor-text | --p-text-color; #242424/#fafafa | Editor text |
--p-diagram-editor-muted | --p-text-muted-color; #616161/#a1a1aa | Secondary text and feedback |
--p-diagram-editor-primary | --p-primary-color; #2563eb | Active controls and derived roles |
--p-diagram-editor-focus | --p-focus-ring-color, then primary | Control focus outlines |
--p-diagram-editor-radius | 0.875rem | Shell radius |
--p-diagram-editor-overlay-radius | 0.75rem | Floating actions, zoom controls, menus and palette tiles |
--p-diagram-editor-control-radius | 0.4375rem | Control/handle radius |
--p-diagram-editor-hover | Primary 7% mixed with surface | Hovered controls |
--p-diagram-editor-active | Primary 13% mixed with surface | Active controls |
--p-diagram-node-fill | Editor surface | Node interior and theme symbol fill |
--p-diagram-node-card-radius | 14px | Ordinary rectangular card corner radius in world units |
--p-diagram-node-stroke | Editor border | Shared shape and theme symbol outline |
--p-diagram-connector | Surface 500/400; #71717a/#a1a1aa | Connector stroke |
--p-diagram-connector-stroke-width | 2px | Connector paths, decoration outlines, midpoint strokes, and connection previews |
--p-diagram-text | Editor text | Diagram labels and symbol text |
--p-diagram-adornment-surface | Node fill | Opaque hollow decorators/adornments |
--p-diagram-adornment-muted | Surface 200/700; #e5e7eb/#3f3f46 | Muted semantic adornments |
--p-diagram-selection | Editor primary | Selection, graph focus, handles and marquee |
--p-diagram-guide-color | Editor primary | Snap guides, drawing and swimlane previews |
--p-diagram-grid-color | Surface 400/500; #a1a1aa/#71717a | Grid |
--p-diagram-preview-fill | Primary 12% mixed with transparent | Drawing preview |
--p-diagram-overlay-background | Editor surface | Default runtime menu, tooltip and inline label editor |
--p-diagram-error | #dc2626/#fca5a5 | Invalid connection feedback |
The table lists theme-entry defaults. Component-local fallbacks apply when shared roles are absent. Load the theme for coordinated light/dark appearance. Grid strokes use the grid color at 30% opacity. Guide color covers snap guides, drawing strokes and swimlane previews; preview-fill covers the drawing interior.
All shapes use the same soft node-stroke and node-fill defaults, including
rectangles, ellipses, diamonds and theme-painted symbols. Explicit saved symbol
paints still take precedence. Only ordinary rectangular cards use the card-radius
role; symbols, frames, lanes and compartment nodes keep their authored geometry.
For cards, the role coordinates the SVG face, HTML content clipping and
selection/focus outline. Palette previews use the same role. Set one CSS length
on the node or its ancestor instead of setting SVG rx or the content's
border-radius separately:
.my-diagram .p-diagram-node[data-node-type='note'] {
--p-diagram-node-card-radius: 2px;
}
.my-diagram .custom-card {
border-radius: var(--p-diagram-node-card-radius, 8px);
}Place this rule in application styles so it can reach the runtime node host.
Custom content can use the inherited role for its own border. Set 0px for
square cards. The unthemed runtime falls back to 8px.
The card radius is screen presentation in world units; it does not change the saved shape, connection attachment, hit testing or export geometry. Use a saved symbol when rounded artwork must travel with the model.
Copied NodeContentUI supplies title/body/footer hierarchy. Its footer separator only appears when the footer has content. Zoom and selection actions share a bordered floating surface; the application still chooses their placement.
#Inheritance and alias resolution
Custom properties inherit. A more local declaration overrides an inherited role;
normal CSS specificity and source order choose between declarations on the same
element. var() aliases resolve where they are declared. The theme defines
selection from primary and adornment-surface from node-fill on :root/:host.
Overriding only primary or node-fill on a descendant does not recompute those
inherited aliases. Set selection, guides, focus, hover/active, text and adornment
roles locally when coordinating a complete design. The same rule applies to
node-stroke, node-fill and panel aliases: set them locally when overriding their
editor surface/border dependencies. A token declaration on a
viewport affects its descendants, not sibling controls. See the explicit mapping
in the practical guide.
See Signal studio for a complete gradient treatment using scoped roles, custom HTML nodes and PrimeVue controls, with switchable palettes and light/dark surfaces.
#Connector width and zoom
--p-diagram-connector-stroke-width accepts a nonnegative CSS length, default
2px. Percentages are unsupported. DiagramViewport.connectorStrokeScaling
defaults to 'viewport', keeping the width in viewport CSS pixels as Diagram
zoom changes. Selection and focus use the same width with their state colors.
Outer application CSS transforms still scale the complete viewport.
<Diagram.Root class="review-diagram" :store="store" page-id="page">
<Diagram.Viewport connector-stroke-scaling="viewport" />
</Diagram.Root>.review-diagram {
--p-diagram-connector-stroke-width: 1.5px;
}Use connectorStrokeScaling="world" when the width must grow and shrink with
the graph. Both modes retain arrow sizes, decoration vertices, dash lengths,
node outlines, and picking tolerance. Width is rendering policy, not saved
geometry. Live CSS is not captured by export. Set export connectorStrokeScaling
and per-connector styles[id].strokeWidth for saved output. SVG, PNG, and browser
print default to readable viewport widths. See Export.
#Copied-part spacing and content
| Variable | Default | Meaning |
|---|---|---|
--p-diagram-ui-panel-padding | 1rem | Panel/heading inset |
--p-diagram-ui-section-gap | 1rem | Section separation |
--p-diagram-ui-group-gap | 0.75rem | Related controls |
--p-diagram-ui-label-gap | 0.25rem | Label-to-control gap |
--p-diagram-node-content-padding | 1rem consumption fallback | Copied NodeContentUI inset |
--p-diagram-node-content-gap | 0.5rem consumption fallback | Copied NodeContentUI region gap |
The first four are theme-entry defaults; the content variables are consumed by the shared stylesheet. They style copied HTML content, not saved bounds, symbol geometry or portable label measurements.
#Copied shell dimensions
| Variable | Comfortable fallback | Compact preset | Meaning |
|---|---|---|---|
--diagram-editor-height | 43rem | Same fallback | Shell/grid minimum height |
--diagram-editor-canvas-height | 27rem; 24rem in the narrow query | Same fallback | Canvas track minimum / responsive track |
--diagram-panel-width | 15.75rem | 14rem | Start panel |
--diagram-inspector-width | 16.5rem | 15rem | End panel |
--diagram-control-height | 2.25rem | 1.9rem | Form/control minimum; compact canvas tools use 2rem |
--diagram-start-width, --diagram-end-width | Panel/inspector fallback | Derived | Internal tracks: absent or collapsible panel 0px |
Collapsible copied sidebars reserve no grid track in either state. Closed panels expose an icon at the canvas edge; open panels overlay the canvas with bounded scrolling content. Their widths still use the panel/inspector variables above, capped to the available canvas width. --diagram-collapsed-sidebar-width is no longer used. Non-collapsible panels retain docked tracks.
Comfortable dimensions use consumption fallbacks, so a wrapper can supply them for the editor and independently placed parts. Compact density sets panel, inspector and control variables directly on the editor. Target that element to replace compact values (with sufficient selector specificity):
.diagram-editor-ui.review-editor[data-density='compact'] {
--diagram-panel-width: 16rem;
--diagram-inspector-width: 18rem;
--diagram-control-height: 2.25rem;
}Prefer the public panel/inspector widths to overriding derived tracks;
the structural stylesheet owns absent, collapsible and docked panel state.
DiagramEditorUI.density defaults to 'comfortable'; dir defaults to 'ltr'.
Logical CSS flips shell placement in RTL; it does not mirror saved geometry or
substitute a layout direction. For non-collapsible panels, container queries move
the end panel below the canvas and then stack start/canvas/end. Collapsible panels
remain bounded overlays at narrow widths.
Actual content and zoom determine readability; density does not resize nodes.
Exact copied binding and projection contracts stay in UI parts.
#Theme-aware and authored colors
Symbols can use currentColor for stroke and nodeFill for the theme interior.
Explicit supported hexadecimal paints retain their authored value.
DiagramLabelRecord.font.color accepts opaque sRGB #RGB/#RRGGBB; omission
inherits the theme. Keep an authored foreground readable against the target
surface in both themes. There is no saved label background field.
Source-backed export evaluates the selected viewport's CSS in an isolated render.
Omit colorScheme to follow the source, or select 'light' or 'dark'. Use CSS
tokens for colors that must change with that mode. Application bindings such as
isDark keep their captured values and branches. Leave background absent
for the export canvas after mode selection.
Detached export retains DiagramExportOptions.theme, supported styles, and
custom-content adapters. Authored label/symbol paint beats theme defaults;
an explicit styles entry merges afterward. Source-backed theme paint objects
and styles overrides are rejected rather than interpreted as CSS. See
Export for the supported CSS scope and failures.
#Geometry and state styling
Use data attributes for entity/interaction
identity and documented classes for connector selection. Nodes use
data-selected='true'; connectors use p-diagram-connector-selected and
:focus-visible. Selected/focused connectors replace their ordinary color with
selection while retaining saved dash and marker geometry. Runtime shapes,
compartments, routes, ports and handle positions come from the scene. Decorative
CSS never changes hit testing, saved bounds, parent-container clipping or export
paint. The card-radius role changes the visible corners of a card's content.
Copied PrimeOne controls also consume PrimeVue component tokens; a local Diagram
accent is not a replacement PrimeVue theme. Body-appended dependency overlays
inherit the app overlay theme, not a Diagram wrapper. Tailwind copied parts own
their HTML/headless control styling. Some legacy optional runtime fallback forms
use general --p-content-*, --p-text-* and --p-primary-* roles; use copied
notation sections for application-owned presentation.
#Interaction states and media behavior
Check ordinary, selected, focus-visible, hovered, unavailable, disabled and pending states. Palette items, ports, handles, guide previews, overlays and status feedback use different roles. Keyboard focus must remain visible even when the selection color is customized. After a font change that affects geometry, invalidate measurements as shown in Geometry measurement.
The shared stylesheet disables palette/Tailwind button transitions and the
Tailwind layout toggle thumb transition under prefers-reduced-motion: reduce.
Custom application motion needs its own handling. No shared forced-colors media
profile certifies every authored symbol or copied dependency. Media emulation
checks establish those emulated conditions, not physical assistive/device
qualification. See Accessibility.