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 variableSource default / dependencyUsed for
--p-diagram-font-familyGeist, ui-sans-serif, system-ui, sans-serifDiagram content and copied control text
--p-diagram-editor-surface--p-content-background; surface 0/900Controls and editor surface
--p-diagram-editor-panelEditor surfacePanel and utilities surfaces
--p-diagram-editor-canvasSurface 50/950; #fafafa/#09090bCanvas background
--p-diagram-editor-border--p-content-border-color; surface 200/700Shell and control borders
--p-diagram-editor-text--p-text-color; #242424/#fafafaEditor text
--p-diagram-editor-muted--p-text-muted-color; #616161/#a1a1aaSecondary text and feedback
--p-diagram-editor-primary--p-primary-color; #2563ebActive controls and derived roles
--p-diagram-editor-focus--p-focus-ring-color, then primaryControl focus outlines
--p-diagram-editor-radius0.875remShell radius
--p-diagram-editor-overlay-radius0.75remFloating actions, zoom controls, menus and palette tiles
--p-diagram-editor-control-radius0.4375remControl/handle radius
--p-diagram-editor-hoverPrimary 7% mixed with surfaceHovered controls
--p-diagram-editor-activePrimary 13% mixed with surfaceActive controls
--p-diagram-node-fillEditor surfaceNode interior and theme symbol fill
--p-diagram-node-card-radius14pxOrdinary rectangular card corner radius in world units
--p-diagram-node-strokeEditor borderShared shape and theme symbol outline
--p-diagram-connectorSurface 500/400; #71717a/#a1a1aaConnector stroke
--p-diagram-connector-stroke-width2pxConnector paths, decoration outlines, midpoint strokes, and connection previews
--p-diagram-textEditor textDiagram labels and symbol text
--p-diagram-adornment-surfaceNode fillOpaque hollow decorators/adornments
--p-diagram-adornment-mutedSurface 200/700; #e5e7eb/#3f3f46Muted semantic adornments
--p-diagram-selectionEditor primarySelection, graph focus, handles and marquee
--p-diagram-guide-colorEditor primarySnap guides, drawing and swimlane previews
--p-diagram-grid-colorSurface 400/500; #a1a1aa/#71717aGrid
--p-diagram-preview-fillPrimary 12% mixed with transparentDrawing preview
--p-diagram-overlay-backgroundEditor surfaceDefault runtime menu, tooltip and inline label editor
--p-diagram-error#dc2626/#fca5a5Invalid 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

VariableDefaultMeaning
--p-diagram-ui-panel-padding1remPanel/heading inset
--p-diagram-ui-section-gap1remSection separation
--p-diagram-ui-group-gap0.75remRelated controls
--p-diagram-ui-label-gap0.25remLabel-to-control gap
--p-diagram-node-content-padding1rem consumption fallbackCopied NodeContentUI inset
--p-diagram-node-content-gap0.5rem consumption fallbackCopied 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

VariableComfortable fallbackCompact presetMeaning
--diagram-editor-height43remSame fallbackShell/grid minimum height
--diagram-editor-canvas-height27rem; 24rem in the narrow querySame fallbackCanvas track minimum / responsive track
--diagram-panel-width15.75rem14remStart panel
--diagram-inspector-width16.5rem15remEnd panel
--diagram-control-height2.25rem1.9remForm/control minimum; compact canvas tools use 2rem
--diagram-start-width, --diagram-end-widthPanel/inspector fallbackDerivedInternal 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.