Skip to main content

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.

info

Admin rights are required to modify the asset or assign it to quotes.

Basic setup

Create a Widget Asset

  1. Navigate to an asset bundle in the asset editor
    • Quote widgets and quote pdfs must be in the same bundle!
  2. Create a new "Widget Asset" of type "Quote"
    • The widget will be created with the default layout
  3. Publish the bundle

Assign to an existing quote

To update the UI of a single quote the following steps are necessary:

  1. Navigate to any quote and start the edit mode
  2. Open the settings dialog (Gear icon at the top right)
  3. Select the according bundle, version and widget
  4. 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):

  1. Ensure to have a working configurator with a working quote or lead setup
  2. Open a new draft of the configurator
  3. Assign the according Asset bundle in the Assets workspace
  4. Navigate to the Finish configuration which creates the lead or quote
  5. At the top-level of the definition add the following properties
    • assetBundleName: "YourBundleName"
    • widgetAssetPath: "AssetName" or widgetAssetPath: "YourFolder.AssetName"
  6. 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.

info

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": []
}
Avoid visual customizations

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

info

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.

PropertyTypeDescription
hideInDraftBoolWhen the quote is in the edit state, it will not display this control. Available for all controls and also hides children, if existent.
hideInPublishedBoolCounterpart 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.
styleObjectDirectly apply CSS styles on the control. The keys must be written in camelCase instead of kebap-case. E.g.: grid-template-columns -> gridTemplateColumns
styleDraftObjectIdentical 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.
labelStringActs 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 & forStringIf 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 $contact in the UI.
  • If only one language is defined, it will always use this one
    • For example, if only de is defined it will always fall back to it, regardless of the selected platform language

Example

{
"main": [
{
"title": "$contact",
"$type": "Accordion"
}
],
"i18n": {
"en": {
"contact": "Contact"
},
"de": {
"contact": "Kontakt"
}
}
}

Text & value templating (LiquidJS)

Upcoming feature

This feature will be added in the near future. In case of specific use cases, feel free to contact us.