Scoping
Variables declared on a component flow downward through all nested components in the same file. They stop at the boundary of a user-defined component file. Pass them explicitly as props, or declare them as global. variables if they are needed everywhere.
Variables
A variable declared in the Main.xmlui file is visible to built-in child components (e.g. Text) at any level.
<App var.message="Hello from App">
<Card id="grandparent">
<Text>Message: {message}</Text>
<Card id="parent" var.message2="Hello from Card">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
<Card id="child">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
</Card>
</Card>
</Card>
</App><App var.message="Hello from App">
<Card id="grandparent">
<Text>Message: {message}</Text>
<Card id="parent" var.message2="Hello from Card">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
<Card id="child">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
</Card>
</Card>
</Card>
</App>A variable declared in a Main.xmlui component is not automatically visible to a user-defined child component.
<App var.message="Hello from App">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyCard />
</App><Component name="MyCard">
<Card>
<Text>Message: {message}</Text>
</Card>
</Component><App var.message="Hello from App">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyCard />
</App><Component name="MyCard">
<Card>
<Text>Message: {message}</Text>
</Card>
</Component>The variable can be passed into a user-defined component.
<App var.message="Hello from App">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyCard message="{message}" />
</App><Component name="MyCard">
<Card>
<Text>Message: {$props.message}</Text>
</Card>
</Component><App var.message="Hello from App">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyCard message="{message}" />
</App><Component name="MyCard">
<Card>
<Text>Message: {$props.message}</Text>
</Card>
</Component>Or the variable can be transposed into the user-defined component by means of the Slot mechanism. The Slot content evaluates in the parent's scope, so it can see parent vars and IDs, but renders inside the child’s layout.
<App var.message="Hello from App">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyCard>
<Text>Message: {message}</Text>
</MyCard>
</App><Component name="MyCard">
<Card>
<Slot/>
</Card>
</Component><App var.message="Hello from App">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyCard>
<Text>Message: {message}</Text>
</MyCard>
</App><Component name="MyCard">
<Card>
<Slot/>
</Card>
</Component>A child component can redeclare a variable.
<App var.message="Hello from App">
<Card id="grandparent">
<Text>Message: {message}</Text>
<Card id="parent" var.message="Hello from parent Card">
<Text>Message: {message}</Text>
<Card id="child" var.message="Hello from child Card">
<Text>Message: {message}</Text>
</Card>
</Card>
</Card>
</App><App var.message="Hello from App">
<Card id="grandparent">
<Text>Message: {message}</Text>
<Card id="parent" var.message="Hello from parent Card">
<Text>Message: {message}</Text>
<Card id="child" var.message="Hello from child Card">
<Text>Message: {message}</Text>
</Card>
</Card>
</Card>
</App>All these rules apply within a user-defined component defined in a file like MyComponent.xmlui.
<App>
<MyComponent />
</App><Component name="MyComponent" var.message="Hello from MyComponent">
<Card id="grandparent">
<Text>Message: {message}</Text>
<Card id="parent" var.message2="Hello from Card">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
<Card id="child">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
</Card>
</Card>
</Card>
</Component><App>
<MyComponent />
</App><Component name="MyComponent" var.message="Hello from MyComponent">
<Card id="grandparent">
<Text>Message: {message}</Text>
<Card id="parent" var.message2="Hello from Card">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
<Card id="child">
<Text>Message: {message}</Text>
<Text>Message2: {message2}</Text>
</Card>
</Card>
</Card>
</Component>A variable declared in a user-defined component can be passed into another user-defined component.
<App>
<MyComponent />
</App><Component name="MyComponent" var.message="Hello from MyComponent">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyOtherComponent message="{message}" />
</Component><Component name="MyOtherComponent">
<Card>
<Text>Passed message: {$props.message}</Text>
</Card>
</Component><App>
<MyComponent />
</App><Component name="MyComponent" var.message="Hello from MyComponent">
<Card>
<Text>Message: {message}</Text>
</Card>
<MyOtherComponent message="{message}" />
</Component><Component name="MyOtherComponent">
<Card>
<Text>Passed message: {$props.message}</Text>
</Card>
</Component>Global variables
A global variable declared in the root element of Main.xmlui, or in the Globals.xs file is visible in all files at any level.
Local variables can shadow global variables:
<App global.count="{42}">
<Text>Current global count: {count}</Text>
<Button onClick="count++">
Increment global count (from Main): {count}
</Button>
<IncButton />
<Button var.count="{0}" onClick="count++">
Increment local count: {count}
</Button>
</App><Component name="IncButton">
<Button onClick="count++">
Increment global count (from component): {count}
</Button>
</Component><App global.count="{42}">
<Text>Current global count: {count}</Text>
<Button onClick="count++">
Increment global count (from Main): {count}
</Button>
<IncButton />
<Button var.count="{0}" onClick="count++">
Increment local count: {count}
</Button>
</App><Component name="IncButton">
<Button onClick="count++">
Increment global count (from component): {count}
</Button>
</Component>Assigning to an undeclared name raises an error toast. Writing
foo = valuein an event handler whenfoowas never declared withvar.foo,<variable>,global.foo, or<global>triggers a runtime error. Always declare the variable on an ancestor component before assigning to it from descendants.
<!-- Produces runtime error: count was never declared -->
<Button onClick="count = count + 1" label="Increment" />
<!-- Declare first, then assign freely from descendants -->
<App var.count="{0}">
<Button onClick="count = count + 1" label="Increment" />
</App>Declaring globals in Globals.xs
Globals can also live in a code-behind file named exactly Globals.xs at the project root. Top-level var and function declarations in that file become globals — equivalent in reach and reactivity to declaring them with global. on the App root, but kept out of the markup.
// Globals.xs
var stations = ['Bakerloo', 'Central', 'Circle'];
function formatStation(name) {
return name + ' line';
}<!-- Main.xmlui — no global. declarations needed -->
<App>
<H2>Station list</H2>
<Items data="{stations}">
<Text>{ formatStation($item) }</Text>
</Items>
</App>stations and formatStation are visible from any component, including user-defined ones, with no prop-threading. Reactivity behaves the same as global. declarations in markup: assigning to stations from any handler re-renders every consumer.
Globals.xs is not the same as Main.xmlui.xs — the latter is the App's component-specific code-behind, and its declarations are local to Main, not global. See Scripting › Code-Behind files for the full distinction.
Component IDs
A component ID declared on a Main.xmlui component is visible to built-in child components (e.g. Text) at any level.
<App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<Card id="parent">
<Text>
{ textBox.value }
</Text>
<Card id="child">
<Text>
{ textBox.value }
</Text>
</Card>
</Card>
</App><App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<Card id="parent">
<Text>
{ textBox.value }
</Text>
<Card id="child">
<Text>
{ textBox.value }
</Text>
</Card>
</Card>
</App>A component ID declared on a Main.xmlui component is not automatically visible to a user-defined child component.
<App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<MyCard />
</App><Component name="MyCard">
<Card>
<Text>Message: {textBox.value}</Text>
</Card>
</Component><App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<MyCard />
</App><Component name="MyCard">
<Card>
<Text>Message: {textBox.value}</Text>
</Card>
</Component>The id can be passed into a user-defined component.
<App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<MyCard textBox="{textBox}" />
</App><Component name="MyCard">
<Card>
<Text>Message: {$props.textBox.value}</Text>
</Card>
</Component><App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<MyCard textBox="{textBox}" />
</App><Component name="MyCard">
<Card>
<Text>Message: {$props.textBox.value}</Text>
</Card>
</Component>Or the component ID can be transposed into the user-defined component by means of the Slot mechanism.
<App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<MyCard>
<Text>Message: {textBox.value}</Text>
</MyCard>
</App><Component name="MyCard">
<Card>
<Slot/>
</Card>
</Component><App var.message="Hello from App">
<TextBox id="textBox" initialValue="{message}" />
<MyCard>
<Text>Message: {textBox.value}</Text>
</MyCard>
</App><Component name="MyCard">
<Card>
<Slot/>
</Card>
</Component>All these rules apply within a user-defined component defined in a file like MyComponent.xmlui.