Combine Content with Backgrounds, Borders, and Headers


Most components in Alexa Presentation Language do not have border or background color properties, so you need to combine multiple components to display backgrounds and borders.

Display a full-viewport background

To display a background color, image, or video, use the Alexa background responsive component. The component fills the full viewport and automatically adjusts to look good on viewports of different sizes. Combine the AlexaBackground component with your other components in a Container. The additional components in the same parent Container are displayed over the background.

To create a background behind your content:

  1. Add the current version of alexa-layouts to the import array in your document:
     {
       "import": [
         {
           "name": "alexa-layouts",
           "version": "1.7.0"
         }
       ]
     }
    
  2. Combine AlexaBackground with your other components in a Container. Put AlexaBackground before the components that you want to display over the background:

     {
       "type": "Container",
       "items": [
         {
           "type": "AlexaBackground",
         },
         {
           "type": "Text",
           "text": "Text displayed over the background.",
         }
       ]
     }
    

    If you put AlexaBackground after your other components, the background will cover up the other components.

  3. At a minimum, set backgroundVideoSource, backgroundImageSource, or backgroundColor to display the background you want.
     {
       "type": "AlexaBackground",
       "backgroundImageSource": "https://d2o906d8ln7ui1.cloudfront.net/images/MollyforBT7.png"
     }
    

    Only one of these properties is used. For example, if you provide both backgroundImageSource and backgroundColor, Alexa displays the background image. See Background source priority in Alexa Background.

    If you do not set any of the three source properties, Alexa displays a default background.

This example uses an image for the background. This example also sets colorOverlay to apply a scrim to the image and make the text easier to read.


The AlexaBackground component uses absolute positioning so that the other components can display on top of it. This means that the properties on the parent Container for positioning child items do not have any affect on the background.

For example, this Container has justifyContent set to end, so Alexa aligns the child components with the bottom of the screen. The paddingBottom property adds space between the last component and the bottom of the screen. Although AlexaBackground is also a child of this same Container, these properties have no effect on the placement of the background and they affect only the Text component:

{
  "type": "Container",
  "justifyContent": "end",
  "paddingBottom": "@spacingLarge",
  "items": [
    {
      "type": "AlexaBackground",
      "backgroundImageSource": "https://d2o906d8ln7ui1.cloudfront.net/images/MollyforBT7.png",
      "colorOverlay": true
    },
    {
      "type": "Text",
      "text": "The <code>justifyContent</code> and <code>paddingBottom</code> properties in this example affect the other child properites, but not AlexaBackground.",
      "style": "textStyleBody",
      "paddingLeft": "@marginHorizontal",
      "paddingRight": "@marginHorizontal",
      "textAlign": "center"
    }
  ]
}
The justifyContent and paddingBottom properties do not affect the background
The justifyContent and paddingBottom properties do not affect the background

Display a header at the top of the screen

A header displayed at the top of your screen can be useful for showing title and subtitle information, as well as branding your skill with an icon.

Use the Alexa header (AlexaHeader) responsive component provided in the Alexa layouts package to add a header to your document.

To add a header to your document

  1. Add the current version of alexa-layouts to the import array in your document:
     {
       "import": [
         {
           "name": "alexa-layouts",
           "version": "1.7.0"
         }
       ]
     }
    
  2. Combine AlexaHeader with your other components in a Container. Position AlexaHeader so that it appears at the top of the viewport, before any other components (unless you are also using AlexaBackground):

     {
       "type": "Container",
       "items": [
         {
           "type": "AlexaHeader",
           "headerTitle": "This is the main header title",
           "headerSubtitle": "This is the header subtitle",
           "headerDivider": true,
           "headerAttributionImage": "https://d2o906d8ln7ui1.cloudfront.net/images/cheeseskillicon.png"
         },
         {
           "type": "Text",
           "text": "Text to display after the header."
         }
       ]
     }
    
  3. Set the properties you want to display in the header (headerTitle, headerSubtitle, and so on). For the available properties, see Alexa Header.

Laying out other components alongside AlexaHeader

You use properties on the Container to determine the positioning of its child components. Avoid creating a layout that interferes with the placement of AlexaHeader at the top of the screen. Depending on the layout you want, you might need to nest additional Containers, like this:

Container
  AlexaHeader
  Container
    Additional components...

Keep the following in mind when defining the layout of the Container that contains AlexaHeader:

  • Alexa background – You can use both AlexaBackground and AlexaHeader together. In this case, put AlexaBackground in the Container first, before AlexaHeader.
  • Layout direction – Leave the direction property on the Container set on the default (column). This creates a vertical layout in which each child component displays below the previous one. If you change this to row, each child component displays to the right of the previous one. This interferes with placing a header across the top of the screen. Nest another Container to create a horizontal layout below AlexaHeader.
  • Absolute vs relative positioning – Be careful if you need to use absolute positioning for any of the other items in the same Container. When you set position to absolute for a component, that component is removed from the normal hierarchy and is positioned relative to the parent, which might make your content overlap the header. It is simpler to use the default position (relative), since this places the subsequent components after the header automatically.

    If you do need to use absolute positioning on a component in the same Container as AlexaHeader, set the top offset large enough to ensure that the component does not overlap the header. Alternatively, use the bottom property to offset the component from the bottom of the viewport.

  • Alignment on the main axis – When the Container direction is column, the justifyContent property controls how the child components are laid out vertically. Use the default value (start) to keep AlexaHeader at the top of the screen. If you change this, vertical alignment for AlexaHeader changes as well. For example, setting justifyContent to end moves all the components in the Container (including AlexaHeader) to the bottom of the viewport.

    If you need to use a different justifyContent setting, nest another Container for those items and set justifyContent there.

  • Alignment on the cross-axis – When the Container direction is column, the alignItems property controls horizontal alignment for the child components. Leave this set to the default (auto). If you change this, horizontal alignment for AlexaHeader changes as well. There are different methods you can use to align the other child components as needed:
    • Nest the other components within another Container and set alignItems on that Container.
    • Keep alignItems set to the default on the parent Container, then override it with alignSelf on each child other than AlexaHeader.
    • Change alignItems on the parent Container as needed, then set alignSelf to stretch on AlexaHeader.
  • Padding – Padding properties at the Container level change the placement of all the Container child components, including AlexaHeader. For example, setting paddingTop pushes your header down, while paddingLeft makes it look indented. To use the padding defined in the AlexaHeader component, leave the padding properties on the Container not set. There are different methods you can use if you need different padding on the other child components:
    • Nest the other components within another Container and set padding properties there.
    • Set the padding properties on the individual child components instead.

    If you want left and right margins of your child components to match the left/right padding of AlexaHeader, set the paddingLeft and paddingRight properties on those components to the marginHorizontal resource provided in the Alexa styles package.

  • Data array inflation – You can bind a data array to a Component with the data property. In this case, Alexa displays the first component in items for which when is true once for each item in the array. This causes your AlexaHeader content to display multiple times, while other components are ignored. To use AlexaHeader in this situation, put AlexaHeader in the firstItem property of the Container instead of items.

The following example uses the alignItems and justifyContent properties to center multiple Text components. To keep the header left-aligned at the top of the viewport, the document uses two Container components:

  • The top-level Container contains AlexaHeader and the second Containeras child components.
  • The second Container sets the alignItems and justifyContent properties and contains the Text components to center. This Container sets the height to "100%", then uses shrink to ensure that the Container uses all of the viewport's vertical space leftover after displaying the header.

In the following example, the Container has a single Text component that displays a value from the array provided in the data property. The AlexaHeader component is in the firstItem property instead of items, so that it displays one time at the top of the screen before the array items.


Click the Data Sources tab and add another item the bakingSteps array. The document updates to add the new item. AlexaHeader remains at the top of the screen. Note that this example isn't designed well for small, round hubs. The full set of content can't fit on the small screen. For a real document, you would use a ScrollView or Sequence to make the list of baking steps scrollable. For details about combining AlexaHeader with scrolling content, see Combine scrolling text with the header and footer.

A footer at the bottom of the screen can show a hint suggesting other phrases the user might say.

Use the Alexa footer (AlexaFooter) responsive component provided in the Alexa layouts package to add a footer to your document.

To add a footer to your document

  1. Add the current version of alexa-layouts to the import array in your document:
     {
       "import": [
         {
           "name": "alexa-layouts",
           "version": "1.7.0"
         }
       ]
     }
    
  2. Combine AlexaFooter with your other components in a Container. Put AlexaFooter last so that it appears at the bottom of the viewport, after any other components

     {
       "type": "Container",
       "items": [        
         {
           "type": "Text",
           "text": "Main body text."
         },
         {
           "type": "AlexaFooter"
         }
       ]
     }
    
  3. Set the hintText property to the text you want to display.

    Use a data source and data transformer to automatically format the hint with the device's wake word.

  4. Configure other Container properties to ensure that footer displays at the bottom of the viewport. See Position the footer, later.

The following example displays a Text component with both a header and footer.


When AlexaFooter is last in the items array for a Container, it displays after all the other components. However, depending on the size of the other components, it might not display at the bottom of the viewport as intended. There are different ways to make sure that AlexaFooter always displays at the bottom of the viewport:

  • Set position on AlexaFooter to absolute and bottom to 0. This offsets AlexaFooter 0 pixels from bottom of the viewport, regardless of the positioning or size of other components. The AlexaFooter responsive component includes bottom padding, so you don't need to include any additional padding. The basic footer example shown previously uses this option.

    The footer overlaps the body content if there isn't enough vertical space for both the body content and the footer. Make sure your body content isn't too large.

  • Make the height of the Container the full viewport height and set grow to "1" on the other component in the Container. The component with grow expands to fill the available empty space in the viewport.

    The footer disappears off the bottom of the screen if there isn't enough vertical space for both the body content and the footer. Make sure your body content isn't too large.

This example has two Text components in the body of the viewport. The second one sets grow to "1" so that the Text bounding box takes up the remaining space:


When displaying longer content, hide the footer on small, round hubs. Use the when property. For example: "when": "${@viewportProfile != @hubRoundSmall}.


Select Hub Round Small in the drop down list and note that the footer disappears.

Use the device wake word in your hints

Users can configure the wake word they use for their devices. You can't assume that the wake word is always "Alexa", so avoid hard-coding text in your footer like "Try 'Alexa, do something else…'" Instead, use a data source and the textToHint transformer to automatically include the device-specific wake word in your hint. This transformer also applies text formatting for consistency.

To use the textToHint transformer

  1. Put your hint text in an object data source, in a property within the properties object. In this example, the hint is in the hintTextToTransform property within the properties object. Only include the specific text of the hint – leave out the wake word and the word "try":
     {
       "footerExampleData": {
         "type": "object",
         "objectId": "footerExampleData",
         "description": "This data source contains data for the footer hint example.",
         "properties": {
           "hintTextToTransform": "do something else with this skill!"
         }
       }
     }
    
  2. Add the textToHint transformer in the transformers array in the data source and set the inputPath of the transformer to the property with your hint text. Provide an outputName property for the transformed value.
     {
       "transformers": [
         {
           "inputPath": "hintTextToTransform",
           "transformer": "textToHint",
           "outputName": "transformedHintText"
         }
       ]
     }
    

    You can omit outputName. In this case, the transformed value is available in the same property specified with inputPath.

  3. In the document, use data binding to set the hintText property of AlexaFooter to the transformer output:
     {
       "type": "AlexaFooter",
       "hintText": "${payload.footerExampleData.properties.transformedHintText}"
     }
    

In the following footerExample data source, the hint text ("do something else with this skill!") is in footerExampleData.properties.hintTextToTransform. The transformer expects to find the text within footerExampleData.properties, so the inputPath just references the property name, hintTextToTransform. The result of the transformation is available in the transformedHintText property.

The following example shows how you use the output of the transformer in your document. The hintText property of AlexaFooter uses data binding to get the transformedHintText value from the footerExampleData data source.

Display the device-configured wake word in the hint
Display the device-configured wake word in the hint

On a device with the default Alexa wake word, the hint displays:

Try "Alexa, do something else with this skill!"

On a device configured with the wake word "Echo", the hint displays:

Try "Echo, do something else with this skill!"

Combine scrolling text with the header and footer

When your content needs to scroll, consider the size of the viewport when placing headers and footers around your ScrollView or Sequence:

  • For small screens – especially small, round hubs – put AlexaHeader inside the scrolling area so that it scrolls out of the way. This maximizes screen space for your content. For example, you could use a structure like this:

    Container
      AlexaBackground
      ScrollView
        Container
          AlexaHeader
          Components with the content that should scroll
    
  • For medium and large screens, put AlexaHeader outside the scrolling area so that it is visible all the time. For example, you could use a structure like this:

    Container
      AlexaBackground
      AlexaHeader
      ScrollView      
          Component with the content that should scroll
          (or a Container if there is more than one component to show)
    

Use the when property to set conditions that determine which components display on the viewport:

{
  "mainTemplate": {
    "items": [
      {
        "when": "${@viewportProfile == @hubRoundSmall}",
        "type": "Container",
        "items": []
      },
      {
        "type": "Container",
        "items": []
      }
    ]
  }
}

Avoid duplicating your content

When you use a when clause on a high-level Container to inflate your document into different layouts, you might duplicate your content in the Container components. This duplication makes it more difficult to update your document as you iterate on your design. For example, in the structure shown previously, the background, header, and scrolling content are all specified in your APL document twice. If you set property values such as the backgroundImageSource directly in the document, you must set it twice and remember to update it in both places as you make changes.

To avoid this problem, APL offers multiple tools for single-sourcing your content:

  • Define constants that you want to use across multiple layouts as resources. For example, you could define custom colors you want to use across all the layouts as resources.
  • Put your content in a separate data source and use data binding to set your properties. A data source is a good option for content you want to generate and change during your skill runtime. Your code can build out the appropriate data source and include it with the Alexa.Presentation.APL.RenderDocument directive.
  • Create a reusable layout with parameters for the properties that might change. Place the layout within mainTemplate and pass the data in to the layout one time.

The following example shows a document in which the header scrolls of the screen for small, round hubs, but remains fixed on larger viewports. The example defines the data needed for both versions of the layout in the data source. The main content to display is a series of paragraphs in an array. Click and drag in the preview to see the content scroll and note that the header remains fixed. Switch to Hub Round Small and note that the header icon scrolls away when when you scroll the content.


The following example implements the same design as a reusable layout with parameters. The mainTemplate contains the single custom layout component and passes the data into the parameters one time. You would still use a data source for your content, although the layout parameters eliminate the duplication.


For more about scrolling text, see:

Draw a border around items

To draw a border around an item on the screen, use a Frame component. This component can have a border, a background color, or both. The Frame takes a single child component to display inside the border. If you want to draw the border around a group of components, put the components in a Container and use the Container as the child component in the Frame.

Border example

This example creates a teal-colored border around a Text component. The padding properties create space between the Text component inside the Frame and the border.

{
  "type": "Frame",
  "borderColor": "@colorTeal800",
  "borderWidth": "5",
  "paddingLeft": "@spacingXSmall",
  "paddingRight": "@spacingXSmall",
  "paddingTop": "@spacingXSmall",
  "paddingBottom": "@spacingXSmall",
  "items": [
    {
      "type": "Text",
      "text": "This <code>Frame</code> has a teal border and transparent background. The <code>Frame</code> contains a single <code>Text</code> component, which is displayed inside of the <code>Frame</code>.",
      "style": "textStyleBody",
      "maxLines": 3
    }
  ]
}

In the following example, the Frame is in a Container with additional components. Alexa draws the border just around the child components of the Frame.


Rounded corners and circular borders

Use the borderRadius properties to create rounded corners. By default, these properties are set to 0 so the corners are straight. Increasing the border radius value creates a rounded corner. Set to a large value to draw the Frame as a circle (if the Frame is square) or an elongated circle or oval (if the Frameis not square).

The Alexa styles package provides pre-defined resources you can use to set the border radius: shapeRoundedRect and shapeCircle.

This example displays two Frame components – one with borderRadius set to 0, and one with it set to shapeRoundedRect.


If you want the border to be a circle, be sure to set the height and width of the Frame to the exact same size. The following example shows two Frame components, each with borderRadius set to shapeCircle. The first Frame has different dimensions for the height and width, so it displays as an elongated circle. The second sets the height and width to the same value, so it displays as a circle. The example uses a resource to set the circle size differently based on the size of the viewport.


Fill the Frame with a background color

The Frame also has a backgroundColor property. Use this when you need a colored background behind an individual item. When you need a background for the full viewport, use the AlexaBackground responsive component instead.

For example, this Frame creates a circle filled with a background color. The specified text displays within the circle.

{
  "type": "Frame",
  "width": "200dp",
  "height": "200dp",
  "backgroundColor": "${backgroundColor}",
  "borderRadius": "@shapeCircle",
  "items": [
    {
      "type": "Text",
      "text": "${text}",
      "textAlign": "center",
      "width": "100%",
      "height": "100%",
      "textAlignVertical": "center"
    }
  ]
}

In this full example, note the following:

  • A custom layout called TextCircleWithBackground defines the Frame. This layout accepts parameters for the color and text to display.
  • The Container places TextCircleWithBackground in mainTemplate. The data property of the Container contains an array of objects, each of which sets a color and text.

When the device displays this document, it displays the TextCircleWithBackground for each item in the data array.



Was this page helpful?

Last updated: Nov 28, 2023