Building Animated SVG Widgets in TIA Portal V17 WinCC Unified

David Krause14 min read
HMI / SCADASiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview of SVG Widgets in WinCC Unified

SVG widgets are reusable, scalable, and scriptable graphical objects that extend the standard library of SIMATIC WinCC Unified runtime (RT) screens. Starting with TIA Portal V17, custom SVG files can be registered as first-class screen objects and animated through SMIL, CSS, or the embedded WebRH JavaScript bundle that ships with the WinCC Unified installation. This article documents the file conventions, project folder layout, animation mechanics, dynamic-property wiring, and runtime event handling required to deploy production-quality animated SVG widgets in WinCC Unified RT (PC, Unified Comfort Panel, and Unified Basic Panel targets).

Unlike raster graphics, SVG widgets scale crisply on the 4:3, 16:9, and 16:10 panel resolutions supported by WinCC Unified, making them ideal for indicators, status icons, gauges, and animated progress controls. Because the runtime rasterizes SVG on the Chromium-based WebRH engine, animations run at full frame rate with negligible CPU overhead compared to bitmap-flip alternatives.

Prerequisites

Before authoring custom SVG widgets, confirm the following are installed and licensed:

  • TIA Portal V17 Update 4 or later (Build 17.0.0.300+) with the WinCC Unified option package installed.
  • WinCC Unified Runtime V17 on the engineering PC, a Unified Comfort Panel (MTP700/1000/1200/1500/1900/2200), or a Unified PC RT instance.
  • SVG-capable text editor — Visual Studio Code with the SVG extension, Notepad++, or the TIA Portal internal XML editor. Editors that do not parse the .svg MIME type may need the file renamed to .svghmi for syntax highlighting.
  • Active TIA Portal project with at least one Unified screen configured and compiled successfully at least once (this populates the runtime data structure).
  • Read access to C:\Program Files\Siemens\Automation\WinCCUnified\WebRH on the engineering PC to inspect the bundled WebRH runtime for API reference.
License note: Custom SVG widgets do not require an additional WinCC Unified license beyond the standard RT license. However, deploying to a Unified Comfort Panel requires the panel-specific Unified RT image to be installed on the device.

SVG Widget File Format and Extension

WinCC Unified distinguishes between two file extensions for SVG content:

Extension Use Case Editable In
.svg Standard W3C SVG 1.1 / 2.0 file. Used when the editor has native SVG syntax highlighting (VS Code, Inkscape, Adobe Illustrator). External SVG editors, browser preview
.svghmi Identical XML content, but the extension is recognized by TIA Portal's integrated editor and by file-type filters in the project tree. TIA Portal, Notepad++, generic XML editors

Both extensions are treated identically by the WebRH engine at runtime. The XML payload must declare the SVG namespace to be rendered:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
  <circle cx="50" cy="50" r="40" fill="none" stroke="#009999" stroke-width="8"/>
</svg>

Save the file using UTF-8 encoding without BOM. The XML declaration on the first line is mandatory; WebRH rejects files that lack <?xml version="1.0" ...?> as malformed.

Project Folder Structure

Custom SVG widgets are stored under the UserFiles directory of the TIA Portal project, which is the sanctioned user-writable area excluded from the project database:

<project_folder>\
  ├─ UserFiles\
  │   └─ SVGControls\
  │       ├─ LoadingSpinner.svghmi
  │       ├─ AnimatedGear.svghmi
  │       └─ StatusPulse.svghmi
  ├─ SystemFiles\
  ├─ Im\n  └─ ...

Deployment procedure:

  1. Create the UserFiles\SVGControls folder under the project root if it does not exist.
  2. Copy .svg or .svghmi files into this directory using Windows Explorer. TIA Portal does not import SVG content through a wizard — the file system is the source of truth.
  3. Close and reopen the TIA Portal project so the project tree refreshes and the new widget appears under UserFiles > SVGControls.
  4. Drag the widget from the project tree onto a WinCC Unified screen, or right-click the widget and select Use in screen.
  5. Recompile the project (HMI > Compile > Software (rebuild all)).
  6. Download the project to the RT (Unified PC or Unified Comfort Panel).
Critical: The TIA Portal project database does not track files inside UserFiles. Backing up the project requires the entire project folder, not just the .ap17 archive. Siemens Teamcenter or version-control integrations must be configured to include the UserFiles tree.

Building an Animated SVG Widget

Three animation methods are supported inside WinCC Unified SVG widgets: SMIL (Synchronized Multimedia Integration Language), CSS keyframe animations, and JavaScript-driven DOM manipulation through WebRH. SMIL is the most portable because it requires no external script execution and works identically on PC, panel, and remote clients.

SMIL Animation Example: Rotating Loading Spinner

The canonical loading indicator is a stroked arc that rotates continuously while a process executes. The <animateTransform> element drives the rotation:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
  <!-- Background ring -->
  <circle cx="50" cy="50" r="40" fill="none" stroke="#e0e0e0" stroke-width="8"/>
  <!-- Foreground arc (90 deg sweep) -->
  <path d="M 50 10 A 40 40 0 0 1 90 50"
        fill="none" stroke="#009999" stroke-width="8" stroke-linecap="round">
    <animateTransform attributeName="transform"
                      attributeType="XML"
                      type="rotate"
                      from="0 50 50"
                      to="360 50 50"
                      dur="1.2s"
                      repeatCount="indefinite"/>
  </path>
</svg>

Save the snippet as LoadingSpinner.svghmi in UserFiles\SVGControls, drag it onto a Unified screen, compile, and download. The arc rotates once every 1.2 seconds, indefinite, around the center of the viewBox.

CSS Animation Example: Pulsing Status Dot

For indicators that pulse on a tag-driven visibility, CSS keyframes are concise and re-styleable from outside the SVG:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50" height="50">
  <style>
    @keyframes pulse {
      0%   { r: 10; opacity: 1.0; }
      50%  { r: 18; opacity: 0.4; }
      100% { r: 10; opacity: 1.0; }
    }
    .pulse-dot { animation: pulse 1.5s ease-in-out infinite; }
  </style>
  <circle class="pulse-dot" cx="25" cy="25" r="10" fill="#ff8800"/>
</svg>

CSS animations are supported by WebRH's Chromium engine. The r attribute is animatable as a CSS property in SVG 2 and is implemented in modern Chromium versions bundled with WinCC Unified V17.

JavaScript-Driven Animation: WebRH API

For animations tied to live tag values — for example a tank-level widget that fills based on an analog tag — JavaScript is the correct tool. The WebRH bundle exposes the screen, the widget host element, and a property-binding API. Embed a script block inside the SVG:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
  <defs>
    <clipPath id="tank-clip">
      <rect x="20" y="10" width="60" height="80" rx="4"/>
    </clipPath>
  </defs>
  <rect x="20" y="10" width="60" height="80" rx="4"
        fill="none" stroke="#333" stroke-width="2"/>
  <rect id="fill" x="20" y="90" width="60" height="0"
        fill="#009999" clip-path="url(#tank-clip)">
  </rect>
  <script type="application/ecmascript"><![CDATA[
    (function() {
      function update(level) {
        // level: 0..100
        var h = Math.max(0, Math.min(100, level)) * 0.8;
        var fill = document.getElementById('fill');
        fill.setAttribute('height', h.toString());
        fill.setAttribute('y', (90 - h).toString());
      }
      // Subscribe to the property exposed by the dynamic widget configuration
      if (window.WebRH && window.WebRH.subscribe) {
        window.WebRH.subscribe('TankLevel', update);
      } else {
        // Fallback: poll a global written by the host screen
        setInterval(function() {
          if (window.TankLevel !== undefined) update(window.TankLevel);
        }, 200);
      }
    })();
  ]]></script>
</svg>

The script is sandboxed to the SVG document context. Cross-widget communication must use window.WebRH event bus or a global variable injected by the host screen's JavaScript interface.

Dynamic Widgets in TIA Portal

The Dynamic Widget framework in TIA Portal V17 exposes selected properties of an SVG widget for tag binding, scripting, and event configuration from the screen editor. To open the configuration UI:

  1. Place the SVG widget on a Unified screen.
  2. Select the widget instance on the canvas.
  3. In the Properties pane, switch from Properties to Dynamic widgets in the toolbar.
  4. Click the Configure button next to the widget name. The dialog lists the SVG element IDs that the runtime discovered, plus any data-rh-property attributes you declared in the source.
  5. Bind each property to a PLC tag, script tag, or local HMI tag. Bindings cycle on the configured update rate (default 1 s, configurable down to 100 ms for high-speed tags).
  6. Optionally configure a click or value-change event to invoke a screen function.

The TIA Portal help path for this dialog is Visualizing processes (RT Unified) > Configuring screens > Configuring objects > Dynamic widgets. Cross-reference this node when building the project documentation deliverable.

Declaring Custom Dynamic Properties

To make an attribute bindable, mark it with the data-rh-property attribute. The runtime then exposes it in the Dynamic Widget dialog:

<rect id="indicator" x="40" y="10" width="20" height="20"
      fill="#888"
      data-rh-property="IndicatorColor"
      data-rh-type="Color"/>

Supported data-rh-type values include Color, Number, Boolean, String, and Enum. The runtime coerces the bound tag value to the declared type before applying the attribute.

WebRH JavaScript API Reference

The WebRH runtime bundle is installed alongside WinCC Unified and contains the API surface available to embedded SVG scripts:

C:\Program Files\Siemens\Automation\WinCCUnified\WebRH\public\libs\webrtpu.bundle.debug.js

This file is the source of truth for the API. Key namespaces and methods exposed to SVG widgets:

Namespace Method / Property Purpose
WebRH.subscribe(name, callback) Subscribe to a named property push from the host screen Real-time tag value delivery
WebRH.publish(name, value) Publish a value to other widgets or the screen Inter-widget communication
WebRH.getProperty(name) Synchronous read of the current bound value Initial-state rendering
WebRH.screen Current screen metadata (name, number, layout) Conditional rendering per screen
WebRH.events.fire(event, payload) Trigger a screen-side event handler Click, value-change, focus events
API stability: The webrtpu.bundle.debug.js file is internal to the WinCC Unified build and is not part of the public TIA Portal Open API. Use the documented dynamic-widget configuration UI where possible. The bundle is provided for diagnostic and reference purposes only.

Mouse Events and Screen Interaction

SVG widgets can capture pointer events through standard DOM event handlers. The most commonly used events in WinCC Unified are:

Event Use Case Notes
click Discrete button press Fires on mouse up at the same target as mouse down
mousedown / mouseup Press-and-hold indicators Use to drive a long-press visual feedback loop
mousemove Drag-to-set sliders, rotary knobs Pair with setPointerCapture for off-target tracking
mouseenter / mouseleave Hover highlights Not available on touch-only panels
touchstart / touchend Touch-screen taps Unified Comfort Panels route touch through the pointer event API

To capture a click and translate it into a screen-side event, dispatch through the WebRH event bus:

element.addEventListener('click', function(e) {
  e.stopPropagation();
  if (window.WebRH && window.WebRH.events) {
    window.WebRH.events.fire('WidgetClicked', { id: 'indicator-1' });
  }
});

The WidgetClicked event becomes available in the screen's event configuration under Events > Widget > WidgetClicked.

SVG Element and Animation Limitations

Not all SVG 1.1 / 2.0 features are equally supported on the WebRH Chromium build. The following table summarizes field-verified constraints observed in WinCC Unified V17 deployments:

Element / Feature Status Workaround
<defs> + <use href="#id"> Rendering inconsistent across some panel Chromium builds Inline the geometry; avoid symbol references
CSS animation of r, cx, cy Supported in modern Chromium; failures on legacy panel images Use animate SMIL element for legacy targets
SVG filters (<filter>) Supported but GPU-disabled on panels Pre-render filter effects as raster fall-back
External image references (<image href="...">) Blocked by runtime sandbox Embed images as base64 data URIs
External font loading Blocked by runtime sandbox Use only system-safe fonts declared inline
<foreignObject> Limited CSS support Restrict to simple HTML for label overlays
Field-tested caveat: On Unified Comfort Panel MTP700 to MTP1200 devices, the <defs> / <use> pattern occasionally renders with stale geometry after a screen switch. To eliminate the glitch, duplicate the geometry inline at each reference site, or wrap the screen in a redraw trigger.

Performance and Memory Considerations

Each SVG widget rendered on a screen consumes memory in the WebRH process proportional to the number of nodes and active animations. For a Unified Comfort Panel with 32 MB of dedicated WebRH memory (typical MTP700–MTP1200 allocation), keep the following budgets per screen:

  • SVG nodes per widget: ≤ 500
  • Concurrent SMIL animations per screen: ≤ 30
  • JavaScript timers (setInterval / setTimeout): ≤ 5 active per widget
  • Total widget count per screen: ≤ 50 (Panels), ≤ 200 (Unified PC RT)

Animations triggered by tag changes should debounce to ≥ 200 ms to avoid saturating the event bus. Use the WebRH.subscribe callback's payload.timestamp field to drop intermediate updates.

Verification and Runtime Testing

Validate the widget through this sequence before deployment to a production panel:

  1. Static test: Open the .svghmi file in a desktop browser (Edge or Chrome) by renaming the extension to .svg. Verify the static layout matches the design intent.
  2. Animation test: Confirm SMIL, CSS, or JS animations play at the expected frame rate. Use the browser's FPS counter in the Performance tab to verify ≥ 30 fps on the development PC.
  3. Tag-binding test: In TIA Portal, set up a simulated PLC or use the PLCSIM Advanced instance. Drive the bound tags through the watch table and confirm the widget updates with no more than one screen refresh cycle of latency.
  4. Compile clean: Run Compile > Software (rebuild all). The Output window must report zero errors and zero warnings related to the SVG widget.
  5. RT download: Download to the target Unified RT. Inspect the runtime log (Diagnosis > Runtime logs) for widget-load errors.
  6. Stress test: Cycle the screen 100 times via the screen-change function to detect any memory leaks in the embedded JavaScript.
  7. Touch verification: On a Unified Comfort Panel, tap each interactive element at least 10 times to confirm event delivery and visual feedback.

Troubleshooting Matrix

Symptom Probable Cause Resolution
Widget does not appear in TIA Portal project tree File placed in wrong directory or TIA Portal not refreshed Confirm file is in UserFiles\SVGControls; close and reopen the project
Widget appears but shows as broken-image icon Malformed XML, missing <?xml?> declaration, or BOM character Re-save as UTF-8 without BOM; validate XML with an external parser
Animation freezes after screen switch Embedded setInterval not cleared on unmount Track interval handles in a closure and clear on unload event
Tag binding does not update Property name mismatch between data-rh-property and dialog binding Re-open Dynamic Widgets dialog; confirm spelling case matches exactly
Click event does not trigger screen function stopPropagation missing, or WidgetClicked not declared in screen event table Verify the event is published through WebRH.events.fire; check screen event configuration
Widget renders correctly in browser but not on panel Unsupported CSS feature or external resource blocked Inline all resources; avoid external font and image references
Compile warning: "UserFiles content not included" Project settings exclude UserFiles from the project archive Open project properties > Archive > enable Include UserFiles
Memory growth over time JavaScript closures retaining DOM references Null out references in unload handler; cap animation set size

Best Practices for Production Widgets

  • Declare viewBox explicitly on every widget. Avoid width="100%" / height="100%" only — the runtime may not propagate size changes correctly to nested SVG elements.
  • Use id attributes only for elements that need JavaScript or dynamic-property access. Random IDs can collide when the same widget is instantiated multiple times on one screen.
  • Limit inline <style> blocks to per-widget rules. Global styles leak across widgets on the same screen.
  • Prefer SMIL for fixed-cycle animations (spinners, pulse dots). SMIL uses the browser's native animation path and avoids the JavaScript event loop.
  • Wrap widget initialization in an immediately-invoked function expression (IIFE) to keep the global scope clean. The WebRH runtime inserts each widget into a shared document context.
  • Document the dynamic-property schema in a comment block at the top of each .svghmi file so that screen designers can wire the widget without opening the source.
  • Version the widgets using a data-rh-version attribute on the root <svg> element. The runtime exposes this value in the diagnostics view, simplifying change control.

Where do I place custom SVG files so TIA Portal V17 picks them up?

Place .svg or .svghmi files in <project_folder>\UserFiles\SVGControls. Close and reopen the project so TIA Portal refreshes the project tree, then drag the widget onto a Unified screen. The folder is not stored in the project database; back up the entire project folder to preserve custom widgets.

What is the difference between .svg and .svghmi extensions?

Both files contain identical XML payload. The .svghmi extension is recognized by TIA Portal's integrated editor and file-type filters; .svg is the W3C-standard extension used by external editors and browser previews. WebRH treats both identically at runtime. Rename freely as long as the XML declaration and SVG namespace are present.

How do I bind a PLC tag to an SVG attribute?

Add a data-rh-property attribute to the SVG element you want to drive, select the widget instance on the Unified screen, and open Properties > Dynamic widgets. In the configuration dialog, bind the declared property to an HMI tag that is itself connected to a PLC tag. The runtime coerces the tag value to the declared data-rh-type (Color, Number, Boolean, String, Enum) and applies it to the SVG attribute on each update cycle.

Can I run JavaScript inside an SVG widget?

Yes. Embed a <script type="application/ecmascript"> block within the SVG. The script runs in the WebRH Chromium context and can access window.WebRH for tag subscriptions, event publishing, and screen metadata. Keep timers capped (≤ 5 active per widget) and clear intervals on the unload event to prevent memory leaks.

Why does my SMIL animation freeze on a Unified Comfort Panel?

SMIL animations are bound to the document lifecycle. When the host screen unloads, the WebRH context may suspend SMIL playback on the next render. To prevent this, drive the animation through a requestAnimationFrame loop in JavaScript, or wrap the screen in a redraw trigger that re-mounts the widget on screen entry. Also confirm the panel image is V17 Update 4 or later, since earlier builds had known SMIL suspend bugs.

Back to blog