You can create new, reusable view components by turning a container into a composite component.
Simply select a container, and at the bottom of the properties panel, click the Turn into a new view component button. After a confirmation dialog, the isolation mode is opened for your newly-created composite component.
To edit an existing composite component, simply double-click it on the view canvas to open the isolation mode.
The isolation mode essentially lets you edit the structure and properties of a composite component in isolation from the rest of the page. To signify this, the rest of the UI is faded out with a translucent stripe pattern.
For any composite component, there's three things to consider:
Structure, i.e. how the composite component's child components are laid out
Properties, i.e. what properties are available for the user to configure after they've dragged it onto the canvas
Internal logic, i.e. what logic is run inside the composite instance, either automatically as part of the component's lifecycle or in reaction to user interaction
Events, i.e. what events the composite component can trigger via its internal logic
Creating the structure for your composite works the same way in isolation mode as outside it: you drag components to the canvas and define their properties and styles. Nested containers can be used to do more complex layouting.
The only difference is the root container for the layout. Outside Isolation mode, the root of your component structure is the page itself, while in isolation mode, it's the root of the composite component.
A composite component can be thought of as a "card" that can be added to any part of your page layout. As such, the style properties available for composite component instance, when selected on the main canvas, include only properties like margin and width, i.e. things that affect the "boundaries" of the composite component.
Conversely, when editing the composite component root inside isolation mode, you can set style properties like padding and background color that affect things inside the composite component boundaries.
Every composite component has a set of root-level properties that define how it functions – you can read more in the Component properties panel guide.
The only property inherent to a composite component is Visibility, i.e. is the component shown in the UI or not.
All other properties are either linked to child component properties (i.e. Input value that is bound to an Input primitive's Value property), or otherwise contain data required by the composite component (i.e. Options that is used by a Pick value flow function in the inner logic canvas).
For example, it makes sense for a card component with a title and body content to expose Title and Content properties: when you drag the card onto the view canvas and select it, you can configure both relevant text contents.
Internally, the card composite has two Text primitives, each with a Content property. The composite component's Title and Content properties are linked to the respective child component properties.
Thus, setting the Title text on the composite triggers the Content property of the title Text primitive inside it to be set.
The bindings are two-way. Let's say we have an Input value root level property in our composite. Inside the composite, we have an Input primitive whose Value property is bound to the root level Input value.
Now, when the user types into the input field, the Input primitive's Value field is changed. The binding then causes the composite's Input value to change. Then, if the Input value on the composite instance was further bound to e.g. a page variable, the changes would propagate further still.
Currently, you cannot define what child component styles are exposed to the composite top level. Instead, you should use theme variables to provide that configurability. This means that instead of black, your component header should be bound to
$colorContentPrimary and so on. This will make your component compatible with the various themes available on the Marketplace.
In isolation mode, you are editing the composite's internal logic – the "engine under the hood". The internal logic exists isolated from the rest of the app logic and is the same for every component instance (unless you edit it). It doesn't and shouldn't know anything that's happening in the rest of the app, as a composite component should work out of the box in any app it's added to.
Thus, you can't use page variables via formulas or use Set page/data/app variable in the inner canvas, as they would be different between apps. (The only exception is theme variables, which are thought to be universal for all apps.)
One way to affect the "outside world" is to change the composite's root level properties via the Set component property flow function – which could then trigger changes via any bound variables.
Of course, directly bound properties described above also affect the outward-facing composite properties.
Another one is via events, described below.
Component primitives expose various kinds of native events: Component tapped, Input value changed, Input field focused and so on. In some cases, you want to expose these events from your child components onto the composite's top level logic canvas, so they can be utilized by whoever's using your component.
For example, a list item might have both a generic tap event on the whole component, as well as a specific tap event on the info icon.
All view components have the
tap event by default. This is a special system event – if there's logic attached to the tap event, clicking/tapping the component shows a tap animation (changing the opacity to 50% translucent) and triggers the event.
You can remove the tap event if you're sure it never makes sense for the user to tap the component as a whole, but there's no harm in keeping it there.
To define a custom event, you need to first add it under the Events section in the component properties (accessible via the Edit properties button in the isolation mode toolbar).
When a new composite component instance is dragged from the component library onto the canvas, it initializes with the default events defined in its properties. If the user removes a default-generated event node, they can re-add it by dragging in a Receive event node and selecting the desired event from the dropdown.
To trigger an outward-facing event registered for the composite component, you simply add a Trigger event node in the right place.
For example, if you want a button inside my composite component to trigger
customEvent when it's tapped, your logic would look like this:
Now, when the button inside your composite is tapped, the
customEvent event is triggered on the component instance's logic canvas.
Since composite components are meant to be isolated from the rest of the app logic, you can only trigger events registered for your composite component.