Logo

Components

We've already seen a number of XMLUI components in action: DataSource,

Built-in components

As an XMLUI developer you'll create user interfaces by combining these with others in the core library, drawing from these categories:
Layout: FlowLayout, HStack, VStack ...

Custom components

You'll also create your own components to combine and extend the built-ins. For example, here's a component that represents the stops on a London tube line.
<App>
  <TubeStops line="Bakerloo"/>
</App>
<Component name="TubeStops">
  <DataSource
    id="stops"
    when="{$props.line}"
    url="https://api.tfl.gov.uk/Line/{$props.line}/StopPoints"
    transformResult="{window.transformStops}"
  />
  <Text variant="strong">{$props.line}</Text>

  <Table data="{stops}">
    <Column width="3*" bindTo="name" />
    <Column bindTo="zone" />
    <Column bindTo="wifi" >
      <Fragment when="{$item.wifi === 'yes'}">
        <Icon name="checkmark"/>
      </Fragment>
    </Column>
    <Column bindTo="toilets" >
      <Fragment when="{$item.toilets === 'yes'}">
        <Icon name="checkmark"/>
      </Fragment>
    </Column>
  </Table>

</Component>
<App>
  <TubeStops line="Bakerloo"/>
</App>
<Component name="TubeStops">
  <DataSource
    id="stops"
    when="{$props.line}"
    url="https://api.tfl.gov.uk/Line/{$props.line}/StopPoints"
    transformResult="{window.transformStops}"
  />
  <Text variant="strong">{$props.line}</Text>

  <Table data="{stops}">
    <Column width="3*" bindTo="name" />
    <Column bindTo="zone" />
    <Column bindTo="wifi" >
      <Fragment when="{$item.wifi === 'yes'}">
        <Icon name="checkmark"/>
      </Fragment>
    </Column>
    <Column bindTo="toilets" >
      <Fragment when="{$item.toilets === 'yes'}">
        <Icon name="checkmark"/>
      </Fragment>
    </Column>
  </Table>

</Component>
window.transformStops = function(stops) {
  return stops.map(function(stop) {
  // Helper to extract a value from additionalProperties by key
    function getProp(key) {
      if (!stop.additionalProperties) return '';
      var propObj = stop.additionalProperties.find(function(p) {
        return p.key === key;
      });
      return propObj ? propObj.value : '';
    }
    return {
      name: stop.commonName,
      zone: getProp('Zone'),
      wifi: getProp('WiFi'),
      toilets: getProp('Toilets'),
      // A comma-separated list of line names that serve this stop
      lines: stop.lines
        ? stop.lines.map(function(line) { return line.name; }).join(', ')
        : ''
    };
  });
}
An instance of TubeStops extracts details for a given tube line. Multiple instances can be arranged on the display using layout components. For example, here's a two-column layout.
<App>
    <FlowLayout>
      <Stack width="*">
        <TubeStops line="victoria"/>
      </Stack>
      <Stack width="*">
        <TubeStops line="waterloo-city"/>
      </Stack>
    </FlowLayout>
</App>
<App>
    <FlowLayout>
      <Stack width="*">
        <TubeStops line="victoria"/>
      </Stack>
      <Stack width="*">
        <TubeStops line="waterloo-city"/>
      </Stack>
    </FlowLayout>
</App>
The TubeStops component:
  • Lives in the components folder. The full path is components/TubeStops.xmlui.
  • Can handle any properties passed in the $props context variable. A calling component can send one or more name="value" pairs like line="Bakerloo".
  • Defines a dynamic data source. When this page embeds <TubeStops line="Bakerloo"/>, the TubeStops component receives a line property used to form the URL that fetches data.
  • Transforms data. When API responses are complex, the expressions needed to unpack them can clutter your XMLUI markup. In this case the component offloads that work to the transformStops function so it can work with a simplified structure.
  • Enriches data. The transformed data has yes/no values for wifi and toilets. TubeStops uses Fragment to display an Icon only for yes values.
When you use custom components to access, transform, and present data, your XMLUI markup stays clean, readable, and easy to read and maintain.
Another way to keep your markup clean: rely on XMLUI's layout and style engine to make your app look good and behave gracefully by default. You can adjust the (many!) settings that define an XMLUI Theme, but you'll rarely need to. The next chapter explains why.
This site is an XMLUI™ app.