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-coloralone 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 withstyle: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 setsstyle:rotate="45"stays rotated when it also writesstyle: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.