APL User-defined Commands


You can define custom commands in your Alexa Presentation Language (APL) document or package.

Overview of user-defined commands

The commands property in the APL document defines a set of commands. A user-defined command can call other APL standard commands.

The following example creates a command called slideInFromRight that calls the AnimateItem command.

{
  "commands": {
    "slideInFromRight": {
      "parameters": [
        "distance",
        {
          "name": "duration",
          "type": "number",
          "default": 300
        }
      ],
      "command": {
        "type": "AnimateItem",
        "easing": "ease-in-out",
        "duration": "${duration}",
        "value": [
          {
            "property": "opacity",
            "from": 0,
            "to": 1
          },
          {
            "property": "transform",
            "from": {
              "translateX": "${distance}"
            },
            "to": {
              "translateX": 0
            }
          }
        ]
      }
    }
  }
}

To use a parameterized command, pass the name of the command as the type.

{
  "type": "TouchWrapper"
  "onPress": {
    "type": "slideInFromRight",
    "duration": 1000,
    "distance": "20vw"
  }
}

In this example, the distance parameter is bound to 20vw in the translateX property animation. The duration of the command is 1000 milliseconds because the value 1000 passed in the duration parameter overrides the default 300 value defined in the command.


Because the command defines a default for duration, you could call this command without providing the duration parameter and get the 300 millisecond animation instead. In contrast, the distance parameter doesn't have a default. If you call the command without distance, the transform.translateX property in the animation defaults to zero, so the "slide" animation is from zero to zero and the component doesn't move.

Command definitions

The command property in the document is a map of command name to a command definition. The command definition contains the following properties:

Property Type Required Description
parameters Array of parameter definitions No Optional named parameters to add to the data-binding context
command, commands Array of commands Yes The array of commands to run
description String No Description of this command

commands

The command property is an implicit sequential block of commands to run. The array of commands supports the standard data-binding with array rules including automatic conversion of a single command into an array of commands and substitution of parameters into the array.

parameters

The parameters are named values that can be passed as arguments. Each parameter is an object with the following properties:

Property Type Required Description
default Any No The default value to apply if this parameter isn't specified. Defaults to empty.
description String No A user-provided description of this parameter
name String Yes The parameter name
type any, array, boolean, color, dimension, integer, map, number, object, string No The type of the parameter. Defaults to any

The parameter name must be a unique name starting with an upper- or lower-case letter and containing no white space ([a-zA-Z][a-zA-Z0-9]*).

As a convenience, a simple parameter name can be used instead of the parameter object (for example, "title" instead of { "name": "title", ... }. This isn't recommended, but does allow compact command definition for cases where no type coercion or defaults values are required.

Command inflation

Commands are inflated with the following algorithm:

  • Each parameter is evaluated and added to the data-binding context.
  • The command array is evaluated.
  • Properties assigned to the object but not matching a named parameter are passed to each command as properties.

For example, note this definition of customPressHandler:

    "commands": {
      "customPressHandler": {
        "description": "Hide the current component and fire an event if checked."
        "parameters": [
          "onChecked",
          {
            "type": "number",
            "name": "opacity",
            "default": 0.5
          }
        ],
        "commands": [
          {
            "type": "SetValue",
            "property": "opacity",
            "value": "${opacity}"
          },
          {
            "type": "Sequential",
            "when": "${event.target.checked}",
            "commands": [
              "${onChecked}"
            ]
          }
        ]
      }
    }

Now assume this custom command is invoked with:

{
  "onPress": {
    "type": "customPressHandler",
    "onChecked": {
      "type": "SendEvent",
      "arguments": ["It was checked!"]
    },
    "delay": 500
  }
}

When the onPress handler fires, the inflated command representation is:

[
  {
    "type": "SetValue",
    "property": "opacity",
    "value": 0.5,
    "delay": 500
  },
  {
    "type": "Sequential",
    "when": "${event.target.checked}",
    "delay": 500,
    "commands": [
      {
        "type": "SendEvent",
        "arguments": ["It was checked!"]
      }
    ]
  }
]

Note the following:

  • The original invocation passed a delay value of 500. The customPressHandler definition doesn't include delay as a parameter, so the delay value was passed into each of the commands in the custom command.
  • The original invocation didn't pass an opacity value, but opacity is defined as a parameter in customPressHandler. So the data-binding context was extended by the default value of opacity, which is 0.5 in this example. That value was used in the SetValue command expansion of ${opacity}.

Nested Expansion of User Commands

You can define user commands that reference other user commands. For example:

{
  "SoftStagger": {
    "description": "General soft-stagger sliding objects from the left or right",
    "parameters": [
      "delay",
      "duration",
      "distance"
    ],
    "commands": [
      {
        "type": "SetValue",
        "property": "opacity",
        "value": 0
      },
      {
        "type": "AnimateItem",
        "values": [
          {
            "property": "opacity",
            "to": 1
          },
          {
            "property": "translateX",
            "from": "${distance}",
            "to": 0
          }
        ],
        "delay": "${delay}",
        "duration": "${duration}",
        "easing": "ease-out"
      }
    ]
  }
}

You can use the SoftStagger command as is and pass in the parameters for delay, duration, and distance. You can also use SoftStagger to define some standard variations for convenience:

{
  "SoftStagger1": {
    "commands": {
      "type": "SoftStagger",
      "delay": 0,
      "duration": 666,
      "distance": 40
    }
  },
  "SoftStagger2": {
    "commands": {
      "type": "SoftStagger",
      "delay": 50,
      "duration": 666,
      "distance": 40
    }
  }
}

You can then add a soft stagger entrance animation to a component with a line like this: onMount:{"type": "SoftStagger2"}.


Was this page helpful?

Last updated: Jan 03, 2025