Adding Text Content to Ignition Perspective Style Classes via CSS

Karen Mitchell8 min read
HMI / SCADAOther ManufacturerTutorial / 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

Perspective style classes in Inductive Automation's Perspective module control visual attributes such as background color, foreground color, border, opacity, and font properties. They do not natively support combining a color indicator with a literal text label inside a single style binding. Designers who want both a colored state (for example, a VRTStatus color) and accompanying text (such as "Running", "Fault", or "°C") typically resort to layering a separate Label component next to the indicator.

This article documents two CSS-based techniques that collapse the color-plus-text pair back into a single styled element: the style class CSS injection workaround (browser/legacy approach) and the theme CSS selector approach (recommended for 8.1.x and later). Both rely on the CSS content property applied via the :after pseudo-element.

Localization warning: The CSS content property does not pass through Ignition's translation system. Reserve it for short, language-neutral symbols (units of measure, degree sign, currency glyphs). Never place translatable user-facing strings inside a CSS content rule.

Prerequisites

  • Ignition 8.0.x or later (Perspective module installed and licensed)
  • Perspective project with at least one View containing a color-driven component (status indicator, LED, tank level, moving analog indicator, etc.)
  • Style Class defined under Project Browser → Styles → Perspective Styles
  • For the theme approach: write access to the active Perspective theme under Project Browser → Styles → Themes
  • Working knowledge of CSS selectors, pseudo-elements, and the MDN reference for the content property

Why Style Classes Cannot Embed Text Natively

A Perspective style class maps a set of visual properties (color, border, font, margin, padding) to a CSS class name. The binding resolves to class="psc-YourClass" on a DOM element. Style classes have no slot for arbitrary textual content because:

  1. Perspective components render SVG or canvas for many chart/indicator widgets. SVG elements do not honor ::before / ::after pseudo-elements at all, except when wrapped in <foreignObject> (which Perspective's chart engine does not emit).
  2. Style class definitions are static JSON in the resource tree — they cannot carry dynamic text payloads from tag bindings.
  3. Text rendering is delegated to Label, TextField, and Display components that own their own DOM nodes.

The standard workaround is to stack a Label component on top of the indicator and bind both the color (via style class) and the text (via a separate binding). When stacking is undesirable, CSS pseudo-element content is the next-best option.

CSS content Property Fundamentals

The CSS content property generates a replaced value that is inserted before or after an element via the ::before or ::after pseudo-element. Per the MDN specification:

  • content: '°C'; appends the literal string °C after the matched element.
  • content: attr(data-unit); reads an HTML attribute and substitutes its value.
  • content: counter(section); uses a CSS counter.

For Perspective, the practical pattern is:

.psc-YourClassName:after {
  content: 'YourTextHere';
  /* optional styling for the appended text */
  margin-left: 4px;
  font-weight: normal;
  opacity: 0.85;
}

The .psc- prefix is auto-generated by Perspective for every style class. Confirm the exact class name in your browser's DevTools Elements panel — it will be of the form psc-XXXXX where XXXXX is a short hash derived from the style class name.

Method 1: CSS Injection via Style Class (Legacy Workaround)

This approach exploits the fact that Perspective style classes accept arbitrary CSS in certain string-typed fields. The original trick uses the backgroundImage field, which accepts a url() value — and CSS parsers will tolerate trailing declarations inside that string. Modern Ignition (8.1.20+) may strip or sanitize this in some build pipelines, so test before relying on it in production.

Step-by-Step

  1. Open Project Browser → Styles → Perspective Styles and click New Style Class.
  2. Name the class, for example, Degree.
  3. Configure the visual properties (foreground color, font, weight, etc.) that match your indicator's intended look.
  4. In the backgroundImage field, paste the following single-line payload:
    } .psc-Degree:after{content:'°'} {

    The leading } closes any prior selector block, and the trailing { opens an empty block that the parser will simply ignore, leaving the .psc-Degree:after rule intact.

  5. Click Commit. Perspective will rebuild the CSS bundle for the active session.
  6. Bind the style class on the target component (for example, a Label or moving analog indicator). The indicator's text content will now show ° immediately after its rendered value.

Variants

Use Case Injection Payload Notes
Degree sign only } .psc-Degree:after{content:'°'} { Compact; ideal for moving analog indicator showing temperature
Degrees Celsius unit } .psc-Degree:after{content:'°C';margin-left:2px} { Works for values < 100; the C may clip under a moving indicator's needle
Currency suffix } .psc-USD:after{content:' USD'} { Use sparingly; never for translated currency names
Percent suffix } .psc-Pct:after{content:'%'} { Common for level bars and KPI labels
Custom glyph via Unicode } .psc-Check:after{content:'\\2713'} { Use full 4-digit hex; verify font has the glyph

Known Limitations of the Injection Trick

  • Does not work on SVG primitives emitted by Perspective charts and moving analog indicators (pseudo-elements are not honored on SVG sub-elements).
  • Does not participate in Ignition's translation pipeline — values are baked at compile time.
  • Hashed class names may change across Ignition upgrades; verify after every major version migration.
  • Some hardened CSP (Content Security Policy) configurations on the gateway reject inline url() payloads.

Method 2: Theme-Based CSS Selector (Recommended)

Beginning with Ignition 8.1, themes in Perspective support direct CSS authoring under Project Browser → Styles → Themes → [YourTheme] → Advanced → Stylesheet. This is the supported location for pseudo-element rules and replaces the injection trick.

Step-by-Step

  1. Open the active Perspective theme (typically default or your site-specific theme).
  2. Navigate to the Stylesheet editor (the Advanced → Stylesheet section in 8.1.x, or the dedicated CSS pane in 8.1.20+).
  3. Append a new rule targeting your style class:
    /* Append °C to any element using the Degree style class */
    .psc-Degree:after {
      content: "°C";
      margin-left: 3px;
      font-size: 0.9em;
      opacity: 0.75;
    }
    
    /* Suffix for percentage style */
    .psc-Percent:after {
      content: "%";
    }
    
    /* Dynamic content pulled from a data-* attribute */
    .psc-UnitLabel:after {
      content: attr(data-unit);
    }
  4. Click Save. Perspective recompiles the theme and pushes the updated CSS to all active sessions.
  5. Apply the style class to your component and verify in the browser.

Theme Method Advantages

  • Full CSS syntax support (no payload-parsing tricks).
  • Survives gateway restarts and project resource imports/exports.
  • Version-controlled alongside theme JSON.
  • Supports @media, @keyframes, and CSS custom properties (--my-color).

Combining Color and Text Without a Second Label

The original poster's scenario — a status color tied to a VRTStatus tag, paired with a textual state name — can be solved with the following architecture:

  1. Create a single Label component with a binding on text returning the status name.
  2. Create a style class mapping each VRTStatus value to a background/foreground color combination.
  3. Apply the style class to the same Label using a property binding on style.classes driven by the same VRTStatus tag.
  4. If a unit suffix is needed, attach it via the theme CSS :after rule described above.

This collapses what previously required two stacked components (color indicator + text label) into one styled label, reducing DOM weight on dense HMI screens.

Verification

After applying either method:

  1. Open the Perspective client in a browser session.
  2. Open browser DevTools (F12) → Elements panel → locate the target element.
  3. Confirm the rendered class contains psc-Degree (or your class name).
  4. Inspect the ::after pseudo-element via DevTools; the appended text should appear in the layout pane.
  5. Force a status change on the bound tag and verify the color updates and the appended text persists across states.
  6. On a moving analog indicator, confirm that the appended unit does not clip behind the needle. If it clips, drop the unit and rely on a static label below the gauge.

Troubleshooting Matrix

Symptom Likely Cause Corrective Action
Appended text never appears Target element is SVG; pseudo-elements unsupported Wrap with a container div or use a Label component instead
Injection payload silently dropped Ignition 8.1.20+ sanitizes inline CSS in style fields Migrate to the theme stylesheet method
Class selector matches nothing Hashed class name changed after upgrade Inspect element, copy exact psc-XXXXX string
Text shows in designer but not client Session cache; theme not recompiled Force-refresh client (Ctrl+F5); confirm theme Save
Appended text overlaps numeric value Indicator needle or bar covers :after region Add padding-right or move to a sibling label
Special character renders as tofu/box Active font lacks the glyph Switch component font to one containing the Unicode glyph (e.g., Noto Sans)
Content does not update on tag change Used literal content: '°C' instead of attr() Switch to content: attr(data-unit) and bind the attribute

Best Practices

  • Use the theme stylesheet for any new development; reserve the injection trick for legacy 8.0.x projects.
  • Keep content values short and language-neutral — never use them for full sentences, button labels, or alarm messages.
  • Document every :after / ::before rule in the theme's README field so future maintainers understand the visual contract.
  • Validate CSS with browser DevTools before each gateway upgrade — class hashes can change.
  • For international deployments, source units from a translation key (via the Label's text property) rather than from CSS content.

FAQ

Can I add arbitrary text to a Perspective style class?

No. Style classes are static visual definitions and have no text payload. You must use either a second Label component or a CSS :after rule in the theme stylesheet to append text.

Does the CSS content property work on Perspective charts?

Not on SVG primitives. Perspective charts emit SVG elements which ignore ::before and ::after. Wrap the chart in a container or use an adjacent label for units.

Will appended CSS text be translated by Ignition?

No. The content property bypasses Ignition's translation system. Use it only for language-neutral symbols (°, %, $, kg) and source all real text from Label bindings.

Why does my injected CSS stop working after an upgrade?

Style class hashes and CSS sanitization rules can change between Ignition minor versions. Re-verify the psc-XXXXX selector in DevTools and migrate to the theme stylesheet method for stability.

Can I bind dynamic text into a :after rule?

Yes — use content: attr(data-unit) and bind a data-unit attribute on the component. For arbitrary tag-driven strings, however, a Label binding remains the cleaner approach.

Back to blog