documentationfor yFiles for HTML 3.0.0.1

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 lets you specify one or more CSS classes for the root element of a graph item’s DOM structure.

The following snippet shows how to define a basic CSS style for nodes using 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. However, depending on the style and the DOM elements it creates, you may need to apply different CSS rules. For example, a PolylineEdgeStyle typically has a stroke property but 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 directly support the CSS class property. Nevertheless, you can still control the color of the arrow based on the CSS class of the related PolylineEdgeStyle. To do this, assign 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, animating state changes of graph items in yFiles for HTML is straightforward.

A simple mouse-over highlight that changes the fill and stroke of a node with a ShapeNodeStyle could be implemented as follows:

<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 larger elements. However, remember that this bypasses the yFiles input mechanism. For edges, it’s generally better to let the itemHoverInputMode determine the hover state of the graph item. This is because it considers the actual hit testing of the style implementation and the current hitTestRadius.

yFiles for HTML doesn’t guarantee that the graph item’s DOM element will persist if you change more than just the cssClass property during a single updateVisual iteration. To reliably trigger CSS transitions, only modify the cssClass property.

When adjusting a property on the style, such as cssClass, also consider that the style might be shared between multiple graph model items. Ensure that you either 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.

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.contentBounds)
  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.contentBounds)
  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 that style the nodes.

No CSS transform Changes Allowed

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

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

Caveats

When working with CSS styling for graph items, there are a few things to keep in mind.

Adjusting the visualization of graph items with CSS happens only in the DOM. yFiles for HTML is not aware of these changes. For example, if you greatly increase the stroke width of an edge using CSS, there will be a mismatch between the hit-testing of the style implementation and the visual representation of the edge. This is usually not a problem when only the color is changed, but it can have undesirable effects when the item’s outline is affected.

For the same reason, avoid using CSS properties on label items that might change the text size, because these changes are not considered when measuring the text and might cause incorrect text placement. Especially for labels, only use CSS properties that affect the visual aspects of the label’s style.

The specific DOM representation of the library styles might change with major yFiles for HTML releases, but the given CSS class will always be added to the root element. Therefore, avoid selecting a specific child element using the root CSS class. The GroupNodeStyle and LabelStyle provide more specific CSS classes for child elements, which allow you to style specific aspects of the style implementation.

Changing a property other than the cssClass property on the style might invalidate the DOM representation, causing the entire DOM subtree to be rebuilt. Therefore, additionally changing the CSS class in the expectation of triggering a transition or animation might not work.

For example, changing the label text and the cssClass in a single rendering cycle will not trigger a transition of the CSS class. To avoid this limitation, wait for a render cycle and then 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 demonstrated in the CSS Item Style demo.