documentationfor yFiles for HTML 2.6

CSS Item Styles

Aside from the mentioned styling option described in this chapter, most style implementations for nodes, edges and labels support custom CSS classes through a cssClass property on the style instance.

This allows to control the item visualization with CSS and enables easy CSS transitions between different states.

The CSS Item Style demo shows applications of this feature by purely relying on the cssClass property to style the graph items. Additionally, it showcases different highlight transitions and animations.

CSS Item Style

The cssClass property can be used to specify one or more CSS classes on the root element of the DOM structure of the graph item.

The following snippet shows how define a basic CSS style for nodes with the cssClass property.

<style>
  .node {
    fill: #17bebb;
    stroke: #094c4b;
    stroke-width: 4px;
  }
</style>

Specifying a CSS class, e.g. cssClass
const nodeStyle = new ShapeNodeStyle({
  cssClass: 'node'
})

This works for most yFiles for HTML styles, though depending on the style and the DOM elements it creates, you need to apply different CSS rules. For example, a PolylineEdgeStyle not only has a stroke property but usually no fill because it is rendered with an SVG path element.

Some styles also create more specific CSS classes for child elements of the visualization if the cssClass property is defined. For more information, see the dedicated documentation for the following styles:

Synchronize fill and stroke with currentColor

The Arrow implementation does not support the CSS class property. Nevertheless, it is still possible to color the arrow dependent on the CSS class of the related PolylineEdgeStyle by assigning CURRENT_COLOR or CURRENT_COLOR, which also works with Automatic Type Conversion:

<style>
  .edge {
    color: #e01a4f;
  }
</style>

Color Edge and Arrows with currentColor
const edgeStyle = new PolylineEdgeStyle({
  cssClass: 'edge',
  stroke: '1px solid currentColor',
  targetArrow: new Arrow({
    fill: 'currentColor',
    type: 'triangle'
  })
})

CSS Item Style Transitions

With CSS classes on item styles, it is very easy to animate state changes of graph items in yFiles for HTML.

A simple mouse-over highlight that changes the fill and stroke of the node with a ShapeNodeStyle could look like this:

<style>
  .node {
    fill: #17bebb;
    stroke: #094c4b;

    /* animate changes */
    transition-property: fill, stroke, stroke-width;
    transition-duration: 0.3s;
    transition-timing-function: ease-in-out;
  }

  .node:hover {
    fill: #e01a4f;
    stroke: #5a0a20;
    stroke-width: 4px;
  }
</style>

Using the :hover pseudo-class often works well for nodes or bigger elements in general, but keep in mind that this skips the entire yFiles input mechanism. Particularly for edges it is usually better to let the itemHoverInputMode decide on the hover state of the graph item because it considers the actual hit testing of the style implementation and the current hitTestRadius.

yFiles for HTML does not guarantee to keep the graph item’s DOM element alive when changing more than just the cssClass property during one updateVisual iteration. So to trigger CSS transitions, make sure to only change the cssClass property.

When adjusting a property on the style, e.g. cssClass, also consider that the style may be shared between multiple graph model items. Either make sure to disable style sharing, or clone the style beforehand.

Exporting Graph Items Styled by CSS

By default, the SvgExport does not consider any external stylesheets. To export graph items that are styled by external CSS rules, the cssStyleSheet property needs to be specified accordingly.

For example, in the case of the mentioned basic node style, the export needs to be configured as follows:

SVG Export with CSS Rules
async function exportSvg(graphComponent) {
  const exporter = new SvgExport(graphComponent.contentRect)
  exporter.cssStyleSheet = `
  .node {
    fill: #17bebb;
    stroke: #094c4b;
    stroke-width: 4px;
    }`
  const svgElement = await exporter.exportSvgAsync(graphComponent)
  return SvgExport.exportSvgString(svgElement)
}

async function exportSvg(graphComponent: GraphComponent): Promise<string> {
  const exporter = new SvgExport(graphComponent.contentRect)
  exporter.cssStyleSheet = `
  .node {
    fill: #17bebb;
    stroke: #094c4b;
    stroke-width: 4px;
    }`
  const svgElement = await exporter.exportSvgAsync(graphComponent)
  return SvgExport.exportSvgString(svgElement)
}

This creates a self-contained SVG including the external CSS rules which style the nodes.

No CSS transform Changes Allowed

The cssClass property is added as-is on the root element of the item’s DOM representation. Typically, yFiles for HTML positions graph items by applying a specific transform on the element.

Therefore, specifying a CSS transform property interferes with the positioning of elements by the GraphComponent, and transitions will result in undesired effects when the item is repositioned by the core graph model.

Caveats

There are a couple of things to keep in mind when working with CSS styling for graph items.

Adjusting the visualization of graph items with CSS is purely on a DOM level. yFiles for HTML does not know about these changes. For example, massively increasing the stroke-width of an edge with CSS results in a mismatch between the hit-testing of the style implementation and the visual representation of the edge. This is neglectable in cases where only the color is changed, but may have undesired effects when the item’s outline is affected.

For the same reason, CSS properties on label items that may result in text size changes should be avoided, since they are not considered for text measuring and therefore might result in wrong text placement. Especially for labels, only CSS properties that affect visual aspects of the label’s style should be used.

The actual DOM representation of the library styles may change with major yFiles for HTML releases, but the given CSS class will always be added to the root element. So selecting a specific child element with the root CSS class is discouraged. The GroupNodeStyle and DefaultLabelStyle provide more specific CSS classes for child elements to allow styling of specific aspects of the style implementation.

Changing a property other than the cssClass property on the style may invalidate the DOM representation such that the entire DOM subtree may be rebuilt. So additionally changing the CSS class in expectation to trigger a transition or animation may not work.

For example, changing the label text and the cssClass in a single rendering cycle does not trigger a transition of the CSS class. To work around this limitation, it is sufficient to await a render cycle and only update the cssClass explicitly:

Pure cssClass Update
// update the label text. This invalidates the label's DOM structure
graph.setLabelText(label, 'Changed label text')

// to animate the CSS class changes, wait for the text to be updated
// because this will rebuild the DOM of the label and thus break any CSS based animations here
await graphComponent.updateVisualAsync()

// the 'pure' cssClass property change (due to the awaited updateVisual) will only update the
// CSS class on the label's DOM structure
label.style.cssClass = `${label.style.cssClass} fade-in`
graphComponent.invalidate()

This approach is also shown in the CSS Item Style demo.