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:
- Add the current version of
alexa-layouts
to theimport
array in your document:{ "import": [ { "name": "alexa-layouts", "version": "1.7.0" } ] }
-
Combine
AlexaBackground
with your other components in aContainer
. PutAlexaBackground
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. - At a minimum, set
backgroundVideoSource
,backgroundImageSource
, orbackgroundColor
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
andbackgroundColor
, 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"
}
]
}
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
- Add the current version of
alexa-layouts
to theimport
array in your document:{ "import": [ { "name": "alexa-layouts", "version": "1.7.0" } ] }
-
Combine
AlexaHeader
with your other components in aContainer
. PositionAlexaHeader
so that it appears at the top of the viewport, before any other components (unless you are also usingAlexaBackground
):{ "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." } ] }
- 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
andAlexaHeader
together. In this case, putAlexaBackground
in theContainer
first, beforeAlexaHeader
. - Layout direction – Leave the
direction
property on theContainer
set on the default (column
). This creates a vertical layout in which each child component displays below the previous one. If you change this torow
, each child component displays to the right of the previous one. This interferes with placing a header across the top of the screen. Nest anotherContainer
to create a horizontal layout belowAlexaHeader
. -
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 setposition
toabsolute
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 defaultposition
(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
asAlexaHeader
, set thetop
offset large enough to ensure that the component does not overlap the header. Alternatively, use thebottom
property to offset the component from the bottom of the viewport. -
Alignment on the main axis – When the
Container
direction iscolumn
, thejustifyContent
property controls how the child components are laid out vertically. Use the default value (start
) to keepAlexaHeader
at the top of the screen. If you change this, vertical alignment forAlexaHeader
changes as well. For example, settingjustifyContent
toend
moves all the components in theContainer
(includingAlexaHeader
) to the bottom of the viewport.If you need to use a different
justifyContent
setting, nest anotherContainer
for those items and setjustifyContent
there. - Alignment on the cross-axis – When the
Container
direction iscolumn
, thealignItems
property controls horizontal alignment for the child components. Leave this set to the default (auto
). If you change this, horizontal alignment forAlexaHeader
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 setalignItems
on thatContainer
. - Keep
alignItems
set to the default on the parentContainer
, then override it withalignSelf
on each child other thanAlexaHeader
. - Change
alignItems
on the parentContainer
as needed, then setalignSelf
tostretch
onAlexaHeader
.
- Nest the other components within another
- Padding – Padding properties at the
Container
level change the placement of all theContainer
child components, includingAlexaHeader
. For example, settingpaddingTop
pushes your header down, whilepaddingLeft
makes it look indented. To use the padding defined in theAlexaHeader
component, leave thepadding
properties on theContainer
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 thepaddingLeft
andpaddingRight
properties on those components to themarginHorizontal
resource provided in the Alexa styles package. - Nest the other components within another
- Data array inflation – You can bind a data array to a
Component
with thedata
property. In this case, Alexa displays the first component initems
for whichwhen
istrue
once for each item in the array. This causes yourAlexaHeader
content to display multiple times, while other components are ignored. To useAlexaHeader
in this situation, putAlexaHeader
in thefirstItem
property of theContainer
instead ofitems
.
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
containsAlexaHeader
and the secondContainer
as child components. - The second
Container
sets thealignItems
andjustifyContent
properties and contains theText
components to center. ThisContainer
sets theheight
to "100%", then usesshrink
to ensure that theContainer
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.
Display a footer at the bottom of the screen
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
- Add the current version of
alexa-layouts
to theimport
array in your document:{ "import": [ { "name": "alexa-layouts", "version": "1.7.0" } ] }
-
Combine
AlexaFooter
with your other components in aContainer
. PutAlexaFooter
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" } ] }
-
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.
- 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.
Position the 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
onAlexaFooter
toabsolute
andbottom
to 0. This offsetsAlexaFooter
0 pixels from bottom of the viewport, regardless of the positioning or size of other components. TheAlexaFooter
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 theContainer
the full viewport height and setgrow
to "1" on the other component in theContainer
. The component withgrow
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
- Put your hint text in an
object
data source, in a property within theproperties
object. In this example, the hint is in thehintTextToTransform
property within theproperties
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!" } } }
- Add the
textToHint
transformer in thetransformers
array in the data source and set theinputPath
of the transformer to the property with your hint text. Provide anoutputName
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 withinputPath
. - In the document, use data binding to set the
hintText
property ofAlexaFooter
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.
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 Frame
is 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
.
shapeRoundedRect
resource might be difficult to see in the code sandbox preview. Zoom your browser to compare the straight corners and rounded corners. Alternatively, copy the sample to the authoring tool and test with a device.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 theFrame
. This layout accepts parameters for the color and text to display. - The
Container
placesTextCircleWithBackground
inmainTemplate
. Thedata
property of theContainer
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.
Related topics
- Display Text on the Screen
- Build Responsive APL Documents
- Text Component
- Alexa Styles Package (
alexa-styles
) - Style Definition and Evaluation
Last updated: Nov 28, 2023