APL Layout

An Alexa Presentation Language (APL) layout is a named composite component, defined in an APL document or package. The layout is a function that expands or inflates into a collection of other named layouts and primitive components. An APL layout supports passing arguments in a parameters array. Inflating an APL layout is conditional, as different components can be inflated based on the current data-binding context.

About layouts

You define layouts in the layouts property of an APL document or package. This property takes a string/object map. You can then invoke the layout in your document by setting the type property of a component to the name of the layout.

For example, consider a HeaderLayoutExample layout that accepts two parameters: title and logo. Within the layout, a Text component uses the value provided in the title parameter and an Image component uses the value provided in the logo parameter.

The HeaderLayoutExample layout inflates into a column-based Container on a round viewport and places the logo before the title. The layout inflates into a row-based Container on a rectangular viewport, which places the logo after the title on the same row.

The following example shows the APL code for HeaderLayoutExample.

{
  "layouts": {
    "HeaderLayoutExample": {
      "description": "A basic header with a title and a logo",
      "parameters": [
        {
          "name": "title",
          "type": "string"
        },
        {
          "name": "logo",
          "type": "string",
          "default": "https://d2o906d8ln7ui1.cloudfront.net/images/cheeseskillicon.png"
        }
      ],
      "items": [
        {
          "when": "${viewport.shape == 'round'}",
          "type": "Container",
          "direction": "column",
          "alignItems": "center",
          "padding": [64,32],
          "items": [
            {
              "type": "Image",
              "source": "${logo}",
              "height": 36,
              "width": 36
            },
            {
              "type": "Text",
              "text": "${title}",
              "style": "textStyleBody",
              "maxLines": 1
            }
          ]
        },
        {
          "type": "Container",
          "direction": "row",
          "padding": [64,32],
          "width": "100%",
          "justifyContent": "spaceBetween",
          "items": [
            {
              "type": "Text",
              "text": "${title}",
              "width": "90%",
              "style": "textStyleBody",
              "maxLines": 2
            },
            {
              "type": "Image",
              "source": "${logo}",
              "height": 50,
              "width": 50
            }
          ]
        }
      ]
    }
  }
}

To invoke the layout in your document, use the layout name for the component type and then pass in the parameters. The following example shows how you invoke the HeaderLayoutExample layout.

{
  "mainTemplate": {
    "parameters": [
      "payload"
    ],
    "items": [
      {
        "type": "HeaderLayoutExample",
        "title": "This is the text to use for the title"
      }
    ]
  }
}

Layout properties

A layout object has the properties shown in the following table.

Property Type Required Description

bind

Array of Binding

No

Expressions to add to the data-binding context.

description

String

No

Provides a description of this layout.

item, items

Array of Component

Yes

The component to inflate. When items contains an array, the layout inflates the first component where the when condition is true.

parameters

Array of parameters

No

An array of parameters you can pass to this layout.

bind

The bind property of a layout extends the data-binding context for the layout and its children. Each binding object in the binding array contains the following:

Property Type Default Description

name

String

Yes

The name to use for this binding. Must be a valid name.

value

Any

Required

The value to assign to this binding.

type


Accepted values: any, boolean, string, number, dimension, color

any

Data type for the binding value.

The bind property evaluates after the parameters property. Bindings are added to the data-binding context in array order. A binding defined later in the array can use the results from bindings defined earlier in the array.

In the following example, Salutation depends on the FormalName binding, which in turn depends on the parameters Title and LastName.

{
  "MyLayout": {
    "parameters": [
      {"name":"Title","default":"Dr."},
      {"name":"FirstName"},
      {"name":"LastName"}
    ],
    "bind": [
      {"name":"FormalName","value":"${Title} ${LastName}"},
      {"name":"Salutation","value":"Dear ${FormalName}"}
    ]
  }
}

To ensure that the bindings you define don't conflict with component property names, capitalize your binding variable names. As shown in the previous example, use Title instead of title.

Primitive APL components also support binding local variables. See the bind property.

item, items

The item property is either a single component or, if items, an array of components. Other layouts can also be part of the items, provided they have already been imported or defined earlier in the layouts object. See Data-binding evaluation.

When items contains an array, the layout inflates the first component where the when condition is true.

parameters

The parameters are named values that you pass a layout when invoking it. Each parameter is an object with the properties shown in the following table.

Property Type Required Description

default

Any

No

The default value to apply if this parameter is not specified. Defaults to empty.

description

String

No

An optional description that explains the purpose of this parameter.

name

String/etc

Yes

The unique parameter name. Names must start with an upper-case or lower-case letter and can't contain white space.

type

Type

No ` The type of the parameter. Defaults to any. ``Accepted values:* any, array, boolean, color, component, dimension, integer, map, number, object, string`

For convenience, you can use a simple parameter name instead of the parameter object. For example, define the parameter as title instead of { "name": "title", ... }. This allows for more compact code when you don't need default values or type coercion for the values you pass to the parameter. Using the full parameter object is recommended for clarity.

Layout inflation

APL uses the following algorithm to inflate a layout:

  1. Evaluate each parameter and add the parameter to the data-binding context.
  2. Evaluate the item or items property using the single child inflation algorithm.
  3. Pass any properties assigned to the layout, but not matching a named parameter, item, or type to the item for evaluation.

For example, the following code defines a simple layout.

"myLayout": {
  "parameters": [
    "title",
    "subtitle"
  ],
  "item": [
    {
      "when": "${viewport.width > viewport.height}",
      "type": "Text",
      "text": "<b>${title}:</b> ${subtitle}",
      "style": "textStyleDisplay1"
    },
    {
      "type": "Text",
      "text": "<b>${title}</b><br>${subtitle}",
      "style": "textStyleDisplay2"
    }
  ]
}

The following example invokes this layout and passes in three parameters: title, subtitle, and color. The color parameter is not specified as a property in myLayout.

{
	"type": "myLayout",
	"title": "Frankenstein",
	"subtitle": "or, The Modern Prometheus",
	"color": "green"
}

Assume the user's device has a landscape screen. The inflation logic does the following:

  1. Add the "title" and "subtitle" parameters to the data-binding context.
  2. Evaluate the item property and find the first component where the when condition evaluates to true. Because the user's device has a landscape screen, APL selects the first component in the items array.
  3. Pass any extra properties to the selected item. This example passed a color property to the layout, which doesn't match any of the defined properties for myLayout. Therefore, pass this property on to the selected item.

The net result is a Text component that looks like the following.

{
	"type": "Text",
	"text": "<b>Frankenstein</b>: or, the Modern Prometheus",
	"style": "textStyleDisplay1",
	"color": "green"
}