Table of Contents
Note

This documentation describes how a native UI view or a native component writes the template directives. For Xml templates see the layout, style, canvas, transition and tooltip directives.

Template directives

In an Xml template, the layout:, style:, canvas:, grid: and transition: directives become the style and class attributes of the element when the view is generated. A native UI view or a native component writes the same CSS properties and classes itself. The automation id, the tooltip and the draggable state are plain attributes, and the other drag and drop directives are native listeners that call dragdropHandlers. Only v-neos-event remains a Vue directive.

A directive behaves like an inline style. Its CSS properties are written in the style attribute of the element. Its classes are read by rules of the neos-directive cascade layer, the highest Neos layer. These rules win over the style of a component, over a style class and over the override of a theme, whatever the specificity of their selectors.

Some directives also give default values to other properties, which they need to have a visible effect. These default values are in the neos-directive-default cascade layer. This layer is above the framework, so the default values apply to every component. It is below the layers of the style classes, so a style class always wins over them:

  • style:border-color alone also gives the element a solid border of 1px, so that the color can be seen. If a style class of the element sets its own border width or style, the element keeps the width and style of the class, with the color of the directive. For example, a style class with a 3px border on an element with style:border-color="red" gives a red border of 3px.
  • A transform directive (style:rotate, style:scale, style:translate...) resets the other transforms of the element to their neutral value (no rotation, no scale). If a style class of the element sets one of them, the element keeps it. For example, an element whose style class sets style:rotate="45" stays rotated when it also writes style:scale="1.2": it is rotated and scaled.
  • A shadow directive gives the same kind of neutral values to the other parts of the shadow (offset, blur, spread). A style class that sets one of these parts keeps it.

The CSS written by the application itself, such as the stylesheet of a native view, is outside the layers, so it wins over every layer. A property written in the style attribute still wins over it. A property set by a rule of the neos-directive layer (a fill size, a transform, a shadow...) does not: a rule of the application that sets the same property on the element wins.

Constant values

Write the CSS properties in style and the classes in class, together with your own classes and styles:

<VerticalLayout
  class="neos-fill-parent-height"
  style="padding: 0.5rem; background: var(--neutral-50)"
>
  ...
</VerticalLayout>

Computed values

Format a computed value with directiveStyles, available in every template without import (also exported by @neos/app). Each formatter takes the value in the Xml template format and returns the CSS value, or undefined when the value is empty (null, undefined, '' or only spaces), which removes the property. A formatter does not check the value: giving a valid value is the responsibility of the developer. When the directive also needs a class, use directiveStyles.has(x) as the condition of the class:

<Text
  class="neos-fill-parent-width"
  :class="{ 'neos-hover-color': directiveStyles.has(hoverColor) }"
  :style="{ color: directiveStyles.color(color), '--neos-hover-color': directiveStyles.color(hoverColor) }"
>
  {{ label }}
</Text>
Formatter Values Result
text(value) Any value The value as a string
has(...values) Any values true when one of the values is not null, undefined, '' nor spaces: condition of a directive class
size(value) auto, a number of pixels or a percentage 'auto', '200px', '33.33%'
length(value) A number of pixels or a percentage, for a minimum or maximum size or a canvas distance '200px', '-5.5px', '50%'
sizeClass(axis, value) fill, auto, a number of pixels or a percentage, axis being 'width' or 'height' 'neos-fill-parent-width', 'neos-fixed-width', undefined for auto
alignSelfClass(axis, value) An alignment, axis being 'horizontal' or 'vertical' 'neos-align-self-horizontal-center'
space(value) 1 to 4 space tokens, in the CSS shorthand order '0.5rem 0.875rem'
buttonMargin(value) 1 to 4 space tokens, for the margin of a Button As space, but none keeps the room that an animated button needs on hover
radius(value) 1 to 4 space tokens or full, in the CSS shorthand order '0.5rem', '9999px 0px'
color(value) A color, see Colors 'var(--primary-500)', 'red'
colors(value) 1 to 4 colors, in the CSS shorthand order 'red var(--primary)'
borderWidth(value) 1 to 4 numbers of pixels, in the CSS shorthand order '1px 2px'
weight(value) regular, strong or stronger 'var(--text-weight-strong)'
degrees(value) A number '-45deg'
pixels(value) A number '-8px'
milliseconds(value) A number '300ms'
translate(value) Two distances in pixels or in percent, such as '10 -50%' '10px, -50%'
transitionProperties(value) Names separated by commas, as in transition:properties, see Transitions 'transform, opacity'
classText(...items) Class strings, objects or arrays, as in :class The class list, such as 'neos-transform neos-shadow'
styleText(style) A style object, as in :style The style text, such as 'color: red; --neos-rotate: 30deg', without the null, undefined or '' values

classText and styleText build the value of a content prop, see Inputs, ActionButton and MenuButton.

Directive reference

In the last column, x is the computed value. Write the result in a :style object, such as :style="{ 'min-width': directiveStyles.length(x) }", and use has(x) as the condition of the classes of the directive.

Directive Constant value Computed value
layout:width, layout:height fill: class neos-fill-parent-width. 200: width: 200px and class neos-fixed-width. auto: width: auto size(x) and class sizeClass('width', x)
layout:min-width, max-width, min-height, max-height min-width: 200px, max-height: 50% length(x)
layout:padding, layout:margin padding: 0.5rem 0.875rem (small medium) space(x), buttonMargin(x) for the margin of a Button
layout:visibility hidden: visibility: hidden. collapsed: class neos-collapsed x === 'hidden' ? 'hidden' : undefined, class if x === 'collapsed'
layout:align-self-horizontal, layout:align-self-vertical Class neos-align-self-horizontal-center, neos-align-self-vertical-top... Class alignSelfClass('horizontal', x)
canvas:top, right, bottom, left top: 8px, left: 50%, see Canvas length(x)
grid:colspan, grid:rowspan and their breakpoint variants --grid-column-span: 2, --grid-row-span-medium: 3 The value as is
style:background, style:color background: var(--neutral-50), color: red, see Colors color(x)
style:border-color border-color: red and class neos-border-color colors(x)
style:border-width border-width: 1px 2px borderWidth(x)
style:corner-radius border-radius: 9999px (full) radius(x)
style:font-weight font-weight: var(--text-weight-strong) weight(x)
style:font-scale, style:opacity --neos-font-scale: 1.2, opacity: 0.6 The value as is
style:letter-spacing letter-spacing: -0.5px pixels(x)
Other style:* directives, such as style:cursor The CSS property, with the value as is The value as is
style:hover-<name> Class neos-hover-<name> and --neos-hover-<name>: var(--primary) color(x), borderWidth(x), weight(x) or the value as is
style:translate, style:rotate, style:scale Class neos-transform and --neos-translate: 10px, -50%, --neos-rotate: 30deg, --neos-scale: 1.2 translate(x), degrees(x), the value as is
style:rotate-x, style:rotate-y Class neos-transform-3d and --neos-rotate-x: 45deg, --neos-rotate-y: 45deg degrees(x)
style:hover-scale Class neos-hover-scale and --neos-hover-scale: 1.1 The value as is
style:shadow-offset-x, -offset-y, -blur, -spread Class neos-shadow and --neos-shadow-offset-x: 8px... pixels(x)
style:shadow-color Class neos-shadow-color and --neos-shadow-color: var(--neutral-900) color(x)
style:hover-shadow-* Class neos-hover-shadow and --neos-hover-shadow-blur: 24px... pixels(x)
transition:duration transition-duration: 300ms milliseconds(x)
transition:easing transition-timing-function: ease-in The value as is
transition:properties transition-property: transform, opacity, see Transitions transitionProperties(x)

The space tokens are none (0px), extrasmall (0.25rem), small (0.5rem), medium (0.875rem), large (1.125rem) and extralarge (1.5rem). The style:hover-<name> directives are hover-color, hover-background, hover-border-color, hover-border-width, hover-font-style, hover-font-weight, hover-opacity and hover-text-decoration.

On a Button, and in the content style of an ActionButton or a MenuButton, also write the border width and style as --neos-border-width and --neos-border-style, so that an animated button keeps them on hover.

Colors

Value CSS value
A theme color, such as primary or neutral-50 var(--primary), var(--neutral-50)
A theme color with alpha, such as primary/0.6 color-mix(in srgb, var(--primary) calc(0.6 * 100%), transparent)
A CSS color keyword, such as red or transparent red, transparent
background var(--background), the theme color
A hexadecimal color, such as #FF000080 #FF000080
A CSS color function, such as rgb(255, 0, 0) rgb(255, 0, 0)

Canvas

The distances of a child of a CanvasLayout are its top, right, bottom and left properties. When both opposite distances of an axis are written, also add the neos-canvas-stretch-horizontal or neos-canvas-stretch-vertical class, so that the own width or height of the child no longer applies and it goes from one edge to the other:

<InputImage class="neos-canvas-stretch-horizontal" style="top: 0px; right: 0px; left: 0px" />
<Badge
  :class="{ 'neos-canvas-stretch-horizontal': directiveStyles.has(left) && directiveStyles.has(right) }"
  :style="{ left: directiveStyles.length(left), right: directiveStyles.length(right) }"
/>

Transitions

Write the transition-property with the CSS properties to animate: the transformations are transform, the shadows box-shadow, style:corner-radius is border-radius and a style:hover-<name> directive is its base property. directiveStyles.transitionProperties(x) translates the names of transition:properties the same way:

<div
  style="overflow: hidden; transition-duration: 300ms; transition-property: max-height"
  :style="{ 'max-height': directiveStyles.length(isOpen ? 200 : 0) }"
/>

Inputs, ActionButton and MenuButton

The visible box of an input or of an action button is an inner element. These components have two props for it:

Prop Type Default Description
contentClass ContentClass undefined Class of the inner element, as a string, an object or an array of them
contentStyle ContentStyle undefined Style of the inner element, as a string, an object or an array of them
Component Inner element
Textbox The text box
Checkbox, Switch, InputTime, InputNumber, InputMask, Combobox, MultiSelect The visible box of the input (the field of a Combobox, not its list of options)
RadioGroup, SelectButton The group of options
ListBox The list
InputSliderDiscrete The slider and its steps
InputFile, InputImage The drop area
Lookup Its inner Combobox or Textbox
StringArrayFormField Each Textbox of the list
ActionButton Its main button and its split button, not the divider nor the menu
MenuButton Its button, not the menu

The components built on one of them, such as InputDate, InputColor, DynamicCombobox, QuickSearch and the form fields, also accept content-class and content-style, as does a UI component or a UI view whose template has one of them at its root: its content props are then added to those of its template, the given style winning property by property.

On an input, write the layout:*, canvas:*, grid:* and style:font-scale directives on the component itself, and the other style:* directives in the content props. On an ActionButton or a MenuButton, only layout:visibility, the alignments, canvas:*, grid:* and style:font-scale go on the component itself, everything else in the content props. Write a transition both on the component and in content-style.

<Textbox
  v-model="name"
  class="neos-fill-parent-width"
  content-style="background: var(--neutral-50)"
/>
<MenuButton
  label="Actions"
  class="neos-align-self-horizontal-right"
  content-style="padding: 0.5rem; border-radius: 9999px"
/>

For a computed content style or class, build a string with directiveStyles.styleText or directiveStyles.classText, from the same objects as :style and :class, so that the component is not rendered again while the value does not change:

<Textbox
  v-model="name"
  :content-style="directiveStyles.styleText({ background: directiveStyles.color(background) })"
/>

Native component or UI view used in an Xml template

The directives written on the usage of a native component or of an embedded native UI view apply to its root element as class and style attributes: keep a single root element and the default attribute inheritance of Vue (no inheritAttrs: false).

The style of the usage wins property by property, but the classes of the root and of the usage add up. A size, an alignment or a visibility written by the usage also adds a neos-usage-<name> class without CSS (neos-usage-width, neos-usage-height, neos-usage-visibility, neos-usage-align-self-horizontal, neos-usage-align-self-vertical), so that a root that sets its own can give way to it. An element with style classes (style:classes) gets these classes too, so that a size, an alignment or a visibility written on it wins over that of its style classes with a Neos target, even with a value such as auto or visible:

<VerticalLayout
  :class="{ 'neos-fixed-width': !directiveStyles.isSetByUsage($attrs, 'width') }"
  :style="{ width: directiveStyles.isSetByUsage($attrs, 'width') ? undefined : '300px' }"
/>

Automation id

The automation:id directive is the data-neos-automation-id attribute. The generator gives each child of a <repeat> the one-based index of its iteration in the data-neos-automation-repeat-index attribute, which a v-for writes itself:

<Card
  v-for="(item, index) in items"
  :key="item.id"
  data-neos-automation-id="ItemCard"
  :data-neos-automation-repeat-index="index + 1"
/>

Tooltip

The tooltip:text directive is the title attribute. On a component that has its own title prop, such as Sidebar, use :title.attr:

<div :title="item.isLocked ? 'Locked by ' + item.lockedBy : undefined">{{ item.name }}</div>
<Sidebar :title.attr="helpText" />

Drag and drop

The dragdrop:draggable directive is the draggable attribute, with the string 'true' or 'false': :draggable="item.canMove ? 'true' : 'false'". The other dragdrop: directives are native listeners that call dragdropHandlers.

See also