Customize the quote UI
With the use of Widget Assets it's possible to customize parts of the Quotes page. It can be used to rearrange the whole details layout, hide and show fields (predefined or Custom fields), change plain text to a Richtext editor and more.
Admin rights are required to modify the asset or assign it to quotes.
Basic setup
Create a Widget Asset
- Navigate to an asset bundle in the asset editor
- Quote widgets and quote pdfs must be in the same bundle!
- Create a new "Widget Asset" of type "Quote"
- The widget will be created with the default layout
- Publish the bundle
Assign to an existing quote
To update the UI of a single quote the following steps are necessary:
- Navigate to any quote and start the edit mode
- Open the settings dialog (Gear icon at the top right)
- Select the according bundle, version and widget
- After confirming your changes the quote will be displayed with your custom UI
Assign widget at configuration finish
To use the widget for new quotes (with our without lead):
- Ensure to have a working configurator with a working quote or lead setup
- Open a new draft of the configurator
- Assign the according Asset bundle in the
Assetsworkspace - Navigate to the
Finishconfiguration which creates the lead or quote - At the top-level of the definition add the following properties
assetBundleName: "YourBundleName"widgetAssetPath: "AssetName"orwidgetAssetPath: "YourFolder.AssetName"
- Afterwards every newly created Quote will use this widget asset
Editing the asset
The whole configuration has an underlying JSON schema. Inside the asset editor there are helpful inline suggestions and a validation with additional hints when hovering over the warnings.
All controls share the $type property. After entering the wanted type in the editor, it will suggest all possible properties for this control.
To get a list of all possible controls check out the info-field "Available UI controls" directly at the top-right of the Widget asset editor.
The $type doesn't always suggest all possible values. The available options are narrowed down based on the other properties present in the object.
For example, in an empty object, only controls that do not require any additional properties are suggested for the $type property. If the object already contains the key property, only controls that support that property are suggested.
Box & Accordion
The main building block of the layout is the Box which can be compared to a div in HTML.
By default it uses the flex layout and can be customized with CSS styles (e.g. to add gap or change to a grid layout).
The children property can then be used to build nested layouts.
The Accordion is similar to the Box but comes with a fixed header (and property title) that lets the children collapse/expand.
Example: Use Box with grid-layout
{
"$type": "Box",
"style": {
"display": "grid",
"gridTemplateColumns": "auto 1fr auto",
"gap": 150
},
"children": []
}
Although the style property is not restricted, we recommend using it primarily for layout and avoiding styling such as backgrounds or similar customizations, as it might clash with the platform styling or themes in the future.
Accessing fields
Controls ending with "...Field"
There are several control types to display and edit the quote fields in different ways. The default widget asset (when creating a new one) contains most of the default fields and should be a good starting point to learn about their usage.
Examples
Field type Text: Can be edited as normal text input, multiline or richtext.
[
{
"property": "notes",
"$type": "TextField"
},
{
"property": "notes",
"$type": "TextField",
"multiline": true
},
{
"property": "notes",
"$type": "RichtextField"
}
]
Field type Number: Can be used as number input or for date selection (stored as Unix timestamp).
[
{
"$type": "NumberField",
"property": "fields.customQuoteDate"
},
{
"$type": "DateField",
"property": "fields.customQuoteDate"
}
]
Item table
The item table control can be customized in the following ways:
- Columns: Change the default order, remove columns, add custom fields as columns
- Expandable detail section: Can be customized with the same building blocks like
Box,TextField, etc.- Comes with a different subset of controls and field properties as they are based on the line items
Because line items have their own type and fields, they also have to be configured individually.
{
"$type": "ItemTable",
"itemDetails": [],
"discountDetails": [],
"markupDetails": []
}
Columns - Default
[
{ "property": "posText" },
{ "property": "name" },
{ "property": "quantity" },
{ "property": "priceNet" },
{ "property": "discount" },
{ "property": "margin" },
{ "property": "finalNet" }
]
Item Details - Default
{
"$type": "Box",
"horizontal": true,
"style": {
"padding": "1rem 5rem",
"alignItems": "start",
"gap": 12
},
"children": [
{
"$type": "Box",
"style": {
"display": "grid",
"gridTemplateColumns": "minmax(0,200px) minmax(0,400px)",
"alignItems": "center",
"rowGap": 8,
"columnGap": 4
},
"children": [
{
"$type": "Box",
"style": {
"gridColumn": "span 2 / span 2"
},
"children": [
{
"$type": "RichtextField",
"property": "description"
}
]
},
{
"$type": "Label",
"text": "$optional",
"variant": "small"
},
{
"$type": "BoolField",
"property": "isOptional",
"showAsSwitch": true
},
{
"$type": "Label",
"text": "$tax",
"variant": "small"
},
{
"$type": "NumberField",
"property": "tax"
},
{
"$type": "Label",
"text": "$sku",
"variant": "small"
},
{
"$type": "TextField",
"property": "sku"
},
{
"$type": "CustomFieldsList"
}
]
},
{
"$type": "Image",
"style": {
"maxHeight": 200,
"maxWidth": 200
}
}
]
}
Discount & Markup details - Default
{
"$type": "Box",
"horizontal": true,
"style": {
"padding": "1rem 5rem",
"gap": 12
},
"children": [
{
"$type": "Box",
"style": {
"display": "grid",
"gridTemplateColumns": "minmax(0,200px) minmax(0,400px)",
"alignItems": "center",
"rowGap": 8,
"columnGap": 4
},
"children": [
{
"$type": "CustomFieldsList"
}
]
}
]
}
Control properties
Please note that this is not a complete list of all properties. When creating a control, refer to the suggestions and validation hints provided directly in the editor for the most up-to-date information.
| Property | Type | Description |
|---|---|---|
| hideInDraft | Bool | When the quote is in the edit state, it will not display this control. Available for all controls and also hides children, if existent. |
| hideInPublished | Bool | Counterpart of hideInDraft. This property is only available for specific controls, as using it more broadly could unintentionally hide content. For example, a user without the required permissions may never be able to enter the edit state and therefore would never see the value. |
| style | Object | Directly apply CSS styles on the control. The keys must be written in camelCase instead of kebap-case. E.g.: grid-template-columns -> gridTemplateColumns |
| styleDraft | Object | Identical to style but will only be applied when the quote is in a draft state. If a style property is existent it will fully replace it without merging or similar. |
| label | String | Acts as label and placeholder for the control when in a quote draft (a11y). In a published state it won't be shown, as a <label> would be technically invalid and adding a normal text would limit layouting flexibility. Instead, add an independent control of type Label which automatically results in a label or span based on the context. |
| htmlId & for | String | If the label property of an editable control isn't used or not available, it's highly recommended to add a htmlId and connect it to a control of type Label with the for property. |
Internationalization (i18n)
Translations are defined in the i18n section of the configuration.
The default widget already contains several translations, which can be modified as needed.
It's only possible to translate texts which are used inside this widget asset
(e.g. field values or rules from the configuration can't be translated right now).
To use a translated string in the widget configuration, prefix the translation key with $.
{
"title": "$contact"
}
The value $contact tells the application to look up the contact key in the i18n section.
- If a translation is missing, it will directly display the string
$contactin the UI. - If only one language is defined, it will always use this one
- For example, if only
deis defined it will always fall back to it, regardless of the selected platform language
- For example, if only
Example
{
"main": [
{
"title": "$contact",
"$type": "Accordion"
}
],
"i18n": {
"en": {
"contact": "Contact"
},
"de": {
"contact": "Kontakt"
}
}
}
Text & value templating (LiquidJS)
This feature will be added in the near future. In case of specific use cases, feel free to contact us.