Creating and using UI component content slots
What are UI component content slots ?
UI components are designed to be reusable UI elements that correspond to a specific feature. However, designing completely generic UI components can be a challenge because there will always be situations where we want to use a common display / functionality but in a slightly different way than in another part of the application.
This is where content slots are useful. They allow any UI view or UI component that calls a UI component to customize parts of what will this UI component display.
Content slots are declared directly in the UI template of a UI component.
UI component with a single unnamed content slot
Declaring the content slot of a UI component
When a UI component only has one content slot, it can simply be declared using the <content /> tag at the place where the customized content should be displayed.
Here is an example of a User UI component that displays a title, the user's name passed as a parameter and a content defined by the parent UI view or UI component :
<vertical-layout>
<heading>User UI component</heading>
<textbox value="@Parameters.Name" label="Name" />
<!-- Content slot that will display content defined by the parent UI view / component -->
<content />
</vertical-layout>
Calling the UI component and passing content in its content slot
When calling a UI component in the UI template of a UI view or another UI component, the customized content for its content slots must be placed inside the UI component tag.
If the called UI component only has one content slot that has no name attribute, the customized content can directly be written inside the UI component tag.
The following example shows a UI view that has a list of users as its data source. It calls the User UI component for each user, passing the user's name as a parameters and customizing the content slot to display an input containing the user's age.
Note
Bindable properties (@Title, @Properties, @Fields, ...) from the UI view or UI component can be used in the content passed to the called UI component.
<vertical-layout>
<heading>User list UI view</heading>
<repeat values="@Datasource" item="User">
<!-- Calling the User UI component for each user in the data source -->
<user name="$User.Name">
<!-- Input that will be displayed at the position of the User UI component content slot -->
<input-number value="$User.Age" label="Age" />
</user>
</repeat>
</vertical-layout>
UI component with multiple named content slots
Declaring the content slots of a UI component
When we want to allow the customization of multiple parts of a UI component, we need to use the name attribute on the different content slots to identify them.
Here is the previous UI component example but with a BeforeInputContent content slot placed before the Name input and an AdditionalContent content slot placed after the Name input :
<vertical-layout>
<heading>User UI component</heading>
<!-- Name content slot -->
<content name="BeforeInputContent" />
<textbox value="@Parameters.Name" label="Name" />
<!-- Named content slot -->
<content name="AdditionalContent" />
</vertical-layout>
Calling the UI component and passing content in its content slots
If the called UI component has named content slots, the customized content for each content slot must be surrounded by tags corresponding to the content slot name attribute.
Warning
UI component content slots names are in kebab case when used in a UI template.
<vertical-layout>
<heading>User list UI view</heading>
<repeat values="@Datasource" item="User">
<user name="$User.Name">
<before-input-content>
<!-- Image that will be displayed at the `BeforeInputContent` content slot position of the User UI component -->
<image name="@Fields.CustomInputImageName" />
</before-input-content>
<additional-content>
<!-- Input that will be displayed at the `AdditionalContent` content slot position of the User UI component -->
<input-number value="$User.Age" label="Age" />
</additional-content>
</user>
</repeat>
</vertical-layout>
Note
Tags placed inside the tag of a UI component and that do not match the name of one of its content slot are ignored.
Displaying a content slot multiple times in a UI component
<content /> and <content name="nameOfTheContentSlot" /> tags can be repeated multiples times in the UI template of a UI component. When the UI component is displayed, the matching customized contents will be displayed at the location of each tag.
Here is the previous UI component example but with two inputs. The BeforeInputContent content will be displayed before each input while the AdditionalContent will only be displayed once :
<vertical-layout>
<heading>User UI component</heading>
<!-- Content slot displayed twice -->
<content name="BeforeInputContent" />
<textbox value="@Parameters.FirstName" label="First name" />
<!-- Content slot displayed twice -->
<content name="BeforeInputContent" />
<textbox value="@Parameters.LastName" label="Last name" />
<!-- Content slot only displayed once -->
<content name="AdditionalContent" />
</vertical-layout>
Calling this UI component in a UI view works in the same way as in the previous UI view example :
<vertical-layout>
<heading>User list UI view</heading>
<repeat values="@Datasource" item="User">
<user first-name="$User.FirstName" last-name="$User.LastName">
<before-input-content>
<!-- Image that will be displayed at each of the `BeforeInputContent` content slot positions in the User UI component -->
<image name="@Fields.CustomInputImageName" />
</before-input-content>
<additional-content>
<!-- Input that will be displayed at the `AdditionalContent` content slot position in the User UI component -->
<input-number value="$User.Age" label="Age" />
</additional-content>
</user>
</repeat>
</vertical-layout>
Calling a UI component without providing content for its content slots
When calling a UI component, filling its content slots is optional. Nothing will be displayed at their location when their content is not provided unless a fallback content is defined for the content slot in the UI component.
Defining a fallback content for the content slots of a UI component
It can sometimes be useful to define a fallback content that will be displayed in a UI component when the UI view or UI component calling it does not provide anything to place in the content slots. This is done in the UI template of the UI component by placing a piece of UI template inside a <content> tag.
Here is an example with fallback contents defined for the content slots of the User UI component :
<vertical-layout>
<heading>User UI component</heading>
<content name="BeforeInputContent">
<!-- Fallback image displayed only when the parent UI view / component does not provide content for this content slot -->
<image name="FallbackInputImage" />
</content>
<textbox value="@Parameters.Name" label="Name" />
<content name="AdditionalContent">
<!-- Fallback text displayed only when the parent UI view / component does not provide content for this content slot -->
<text>No additional content.</text>
</content>
</vertical-layout>
Both the fallback contents will be displayed if the User UI component is called this way :
<vertical-layout>
<heading>User list UI view</heading>
<repeat values="@Datasource" item="User">
<user name="$User.Name" />
</repeat>
</vertical-layout>
In the following example, the only fallback content displayed will be the one defined for the AdditionalContent content slot :
<vertical-layout>
<heading>User list UI view</heading>
<repeat values="@Datasource" item="User">
<user name="$User.Name">
<before-input-content>
<image name="@Fields.CustomInputImageName" />
</before-input-content>
</user>
</repeat>
</vertical-layout>
When a content slot is used multiple times in a UI component, its fallback content has to be defined each time. The fallback content can be different at each location of the content slot :
<vertical-layout>
<heading>User UI component</heading>
<!-- BeforeInputContent content slot used multiple times -->
<content name="BeforeInputContent">
<!-- Fallback content for the first location of the content slot -->
<image name="FallbackInputImage" />
</content>
<textbox value="@Parameters.FirstName" label="First name" />
<!-- BeforeInputContent content slot used multiple times -->
<content name="BeforeInputContent">
<!-- Different fallback content for the second location of the content slot -->
<text>Missing image<text>
</content>
<textbox value="@Parameters.LastName" label="Last name" />
<content name="AdditionalContent">
<!-- Fallback content -->
<text>No additional content.</text>
</content>
</vertical-layout>