Viewport Object in the Data-binding Context


The data-binding context for an Alexa Presentation Language (APL) document includes a viewport property that describes the operating characteristics of the display device.

Viewport object example

For example, the viewport object on the original Echo Show reports the following properties:

{
  "viewport": {
    "width": 1024,
    "height": 600,
    "pixelWidth": 1024,
    "pixelHeight": 600,
    "shape": "rectangle",
    "dpi": 160,
    "theme": "dark",
    "mode": "hub",
    "autoHeight": false,
    "autoWidth": false,
    "minHeight": 600,
    "minWidth": 1024,
    "maxHeight": 600,
    "maxWidth": 1024
  }
}

Your document can use conditional logic to provide different experiences for different viewports.

Properties

The viewport object has the properties shown in the following table.

Property Type Description

autoHeight

Boolean

When true, the viewport supports auto-sizing height.

autoWidth

Boolean

When true, the viewport supports auto-sizing width.

dpi

Integer

The pixel density of the viewport.

height

Positive Dimension

Default height in display-independent pixels (dp).

maxHeight

Positive Dimension

Maximum height in display-independent pixels (dp).

maxWidth

Positive Dimension

Maximum width in display-independent pixels (dp).

minHeight

Positive Dimension

Minimum height in display-independent pixels (dp).

minWidth

Positive Dimension

Minimum width in display-independent pixels (dp).

mode

Mode

The operating mode.

pixelHeight

Integer

Default height in pixels.

pixelWidth

Integer

Default width in pixels.

shape

Possible values: round or rectangle

Shape of the viewport.

theme

String

The preferred color scheme.

width

Positive Dimension

Default width in dp.

autoHeight

When true the APL document can adjust its height within the range minHeight and maxHeight. When false, the viewport is always exactly height units tall.

The autoHeight property is a convenience property for quickly establishing if the viewport might change in height. This property is equivalent to ${viewport.height != viewport.maxHeight || viewport.height != viewport.minHeight}.

autoWidth

When true the APL document can adjust its width within the range minWidth and maxWidth. When false, the viewport is always exactly width units tall.

The autoWidth property is a convenience property for quickly establishing if the viewport might change in width. This property is equivalent to ${viewport.width != viewport.maxWidth || viewport.width != viewport.minWidth}.

dpi

The display-independent pixel (dp) measurement of a screen is an artificial value that represents the visual size of the screen assuming that the screen is held at a mobile-phone viewing distance and has a pixel density of approximately 160 pixels per inch (the original iPhone screen was 163 pixels per inch). Two screens viewed at the same distance with the same physical size have approximately the same dp dimensions regardless of the actual pixel density of the screen.

The dots-per-inch (dpi) of a viewport is an artificial value that reflects the visual size of a point or pixel relative to the observer, and it doesn't match the actual pixels-per-inch size of the screen. The formula for dpi is:

dpi = 160 * (pixelSize / dpSize)

The following DPI values are supported: 120, 160, 213, 240, 320, 480, 640.

In practice the manufacturer selects the dpi size of the screen based on physical dimensions and expected viewing distance, and then calculates the dp size based on that dpi. For example, manufacturers recommend a 1080p television watching distance of approximately twice the diagonal measurement of the television screen, regardless of the actual screen size. Because the apparent visual size of the TV to the viewer is constant, all 1080p televisions have dpi=320, with pixelHeight of 1080 and height of 540.

height

The viewport height property is the suggested display-independent pixel height of the viewport. When autoHeight is false, this height is strictly enforced. The viewport occupies exactly that height on the screen. When autoHeight is true, this height is a recommended default height, but the actual height might vary between minHeight and maxHeight. The APL document displayed within the viewport clips to the bounds of the viewport.

For more about how the size properties work together, see About viewport size.

maxHeight

The viewport maxHeight property is the maximum allowed display-independent pixel measurement of the height of the viewport. When autoHeight is false, this is the same as the viewport height.

For more about how the size properties work together, see About viewport size.

maxWidth

The viewport maxWidth property is the maximum allowed display-independent pixel measurement of the width of the viewport. When autoWidth is false, this value is the same as the viewport width.

For more about how the size properties work together, see About viewport size.

minHeight

The viewport minHeight property is the minimum allowed display-independent pixel measurement of the height of the viewport. When autoHeight is false, this value is the same as the viewport height.

For more about how the size properties work together, see About viewport size.

minWidth

The viewport minWidth property is the minimum allowed display-independent pixel measurement of the width of the viewport. When autoWidth is false, this value is the same as the viewport width.

For more about how the size properties work together, see About viewport size.

mode

The mode property describes the expected use of the device. The mode property returns one of the following values:

Value Description Common input types Examples
auto Used by the driver in a vehicle. Touch Automobile dashboard, built-in aircraft display
hub A table-top or fixed-position devices. Touch (when close) Amazon Echo Show, counter-top appliance
mobile A handheld device carried by the user. Touch Mobile phone, tablet computer
pc A desktop or laptop computer. Keyboard, mouse, track pad Desktop, laptop computer
tv A television or projected display. Remote control Television, billboard

The input types listed in the table are representative and not guaranteed to exist for a particular device mode.

A single device can report different modes at different times. For example, a tablet computer reports as a mobile device at most times, but might report as a hub device when docked in a docking station. Proximate devices often report as different modes. For example, in an automobile the device built into the dashboard reports as auto, the device installed in the ceiling behind the driver for passengers reports as tv, and the mobile phone held by a passenger reports as mobile.

The list of modes might change. When you use mode in conditional logic, assume that the property could return an unrecognized value. Always provide a default definition for any properties or components that depend upon mode.

pixelHeight

The pixelHeight property is the pixel measurement of the height of the viewport. This is equal to ${viewport.height * viewport.dpi / 160}. The pixelHeight property is provided as a convenience to use when selecting suitable bitmap images to display.

pixelWidth

The pixelWidth property is the pixel measurement of the width of the viewport. This is equal to ${viewport.width * viewport.dpi / 160}. The pixelWidth property is provided as a convenience to use when selecting suitable bitmap images to display.

shape

The shape of the screen returns either round or rectangle.

theme

The theme reflects the basic color scheme in use on the device. The theme is a string value. You can set the theme in the APL document in the theme property. When not set in the document, the device sets it to either "light" or "dark":

  • light: Dark text drawn on a light background
  • dark: Light text drawn on a dark background

You can use the theme when you define styles in your document or package. The following example shows two styles that adjust based on the theme.

{
  "styles": {
    "styledText": {
      "values": [
        {
          "color": "${viewport.theme == 'dark' ? 'white' : 'black'}"
        }
      ]
    },
    "styledFrame": {
      "values": [
        {
          "backgroundColor": "${viewport.theme == 'dark' ? '#096484' : '#74B6CF'}"
        }
      ]
    }
  }
}

In your document, you can choose to ignore the theme entirely or override the device-supplied value with a custom theme. For example, the following document creates a custom "fancy" theme. Change the value of the theme property and note that the text changes color.


This approach provides flexibility when the styles and resources are in a separate APL package. You can switch between various custom appearances with a single theme choice.

About viewport size

The viewport object has height (autoHeight, height, minHeight, and maxHeight) and width (autoWidth, width, minWidth, and maxWidth) properties that define the drawing size of the APL document.

Usually, the viewport has a fixed size. For example, an APL document might display as a full screen on an Alexa device, where the size of the viewport is fixed to the size of the screen.

The following example shows the viewport object for a full screen display of an APL document on a 1280 by 1024 screen with a 320 dpi.

"viewport": {
  "autoHeight": false,   // The height is fixed
  "autoWidth": false,    // The width is fixed
  "dpi": 320,
  "height": 512,         // 1024 pixels @ 320 dpi = 512 dp
  "maxHeight": 512,      // Same as height
  "maxWidth": 640,       // Same as width
  "minHeight": 512,      // Same as height
  "minWidth": 640,       // Same as width
  "pixelHeight": 1024,
  "pixelWidth": 1280,
  "shape": "rectangle",
  "width": 640           // 1280 pixels @ 320 dpi = 640
}

Sometimes, the size of the viewport might be flexible in height or width. For these viewports, the autoHeight or autoWidth properties report true.

For example, consider a displayed APL document where the height is fixed to 400 dp, but the width of the document might vary between 200 dp and 600 dp. The viewport object reports the following.

"viewport": {
  "autoHeight": false,   // The height is fixed
  "autoWidth": true,     // The width can vary
  "dpi": 320,
  "height": 400,         // The height is fixed to 400 dp
  "maxHeight": 400,      // Same as height
  "maxWidth": 600,       // The maximum width is 600 dp
  "minHeight": 400,      // Same as height
  "minWidth": 200,       // The minimum width is 200 dp
  "pixelHeight": 800,    // 400 dp @ 320 dpi = 800 pixels
  "pixelWidth": 800,     // 400 dp @ 320 dpi = 800 pixels (default width)
  "shape": "rectangle",
  "width": 400           // The default width is 400 dp
}

For details about how APL calculates the size of the top component for variable viewports, see Understanding viewport layout.

Components aren't required to match the viewport size

The size of the top component in the view hierarchy isn't required to match the size of the viewport. When the sizes don't match, clipping occurs or blank spaces display. The top-left corner of the component is attached to the top-left corner of the viewport. For example, assume a fixed viewport size of 640 dp by 512 dp with the following APL document.

"mainTemplate": {
  "item": {
    "type": "Frame",
    "width": 2000,
    "height": "50vh",
    "backgroundColor": "green"
  }
}

The top-level Frame has a width of 2000 dp and a height of 256 dp, but it displays within the bounds of the 640x512 viewport. The device displays blank space below the document, filled in with the document background if set. The right side of the Frame runs off the side of the screen and isn't visible.

Viewport height and width reflect the current screen orientation and dimensions

The viewport height and width reflect the current screen orientation and dimensions. A tablet computer with a 1024 by 768 pixel screen showing a fulls screen APL document reports a viewport pixelWidth of 768 in portrait mode and 1024 in landscape mode. The fact that the screen is rotated isn't reported to the APL document.

Understand viewport layout

This section describes how the size of the viewport and the size of the top-level component in an APL document interact. Note the following definitions:

  • Viewport – Defined by the APL runtime. The viewport represents the space that the APL document renders within.
  • Top-level component size – Defined by the APL document. All other components in the document are clipped to the bounds of the top-level component. The top-level component is often a Container, but can be any component.

The width and height calculations use the same algorithm. The following sections describe how APL calculates the output widths of the viewport and top-level component. The output heights of the viewport and top-level component are calculated in the same way.

The algorithms described here are a simplified version of the actual Flexbox Box Layout Module and CSS Box Sizing Module logic. Refer to those documents for the complete details.

This section assumes that the viewport and component properties are well-ordered when defined. This means that they adhere to the following rule:

viewport.minWidth <= viewport.width <= viewport.maxWidth   (if both defined)
component.minWidth <= component.width <= component.maxWidth (if both defined)

Refer to the CSS Box Sizing Module specification for a discussion of how these properties interact when they aren't well-ordered.

Fixed viewport

Most APL runtimes place documents in a fixed-size viewport. A fixed viewport has the same value for the viewport width, minWidth, and maxWidth.

viewport.minWidth == viewport.width == viewport.maxWidth
viewport.autoWidth = false

The following rules use the top-level component properties for width, minWidth, and maxWidth to determine the output width of the component.

When component width is an absolute dimension

When the component width is an absolute dimension, the output width is the specified width value clamped to the component maxWidth and minWidth properties. The size of the viewport isn't used in the computation. Examples of absolute dimensions include values such as 25px, 10vw, or 30.

The following pseudo-code shows this calculation.

if TypeOf( component.width ) == AbsoluteDimension:
  w = Clamp( component.width, component.minWidth, component.maxWidth )
  component.output.width = w
  Layout( component, width=w )

Component width is a relative dimension

When the component width is a relative dimension, the output width is the product of the component width and the viewport width clamped to the component maxWidth and minWidth. Examples of relative dimensions include values such as 25% and 50%.

The following pseudo-code shows this calculation.

if TypeOf( component.width ) == RelativeDimension:
  w = component.width * viewport.width
  w = Clamp( w, component.minWidth, component.maxWidth )
  component.output.width = w
  Layout( component, width=w )

Component width is auto

If the component width is auto, the output width depends on whether the maxWidth has a value. If maxWidth has a value, the component tightly wraps its children and clamps to the component maxWidth and minWidth. If maxWidth doesn't have a value, the component fills the viewport.

The following pseudo-code shows this calculation.

if TypeOf( component.width ) == AutoDimension:
  if IsDefined( component.maxWidth ):
    w = Layout( component, width=Undefined ).getWidth()
    w = Clamp( w, component.minWidth, component.maxWidth )
  else:
    w = viewport.width
  component.output.width = w
  Layout( component, width=w )

In all three of the these scenarios, the top-level component output width can be smaller or larger than the viewport width. APL positions the top-left corner of the component at the origin of the viewport (the top-left corner). When the component output width is larger than the viewport width, the viewport clips the right side of the component. When the component output width is smaller, the document background is visible on the right-hand side of the viewport.

Variable viewport

Some APL runtimes support variable-size viewports. A variable viewport expands or contracts to adjust to the size of the APL document in either width, height, or both. For example, a runtime displaying a horizontal list of APL documents might allow the individual documents to vary in width to allow some documents to take extra horizontal space. A variable viewport has different values for viewport width, minWidth, and maxWidth.

viewport.minWidth <= viewport.width <= viewport.maxWidth
viewport.minWidth < viewport.maxWidth
viewport.autoWidth = true

The final viewport output width is in the range [minWidth, maxWidth].

The viewport width is the default output width of the viewport. This value is used in two ways:

  • When the component width is set to a relative dimension, the viewport output width is fixed to the viewport width. Usually the component width is 100%, indicating that the component wants to be the default width of the viewport.
  • Resource calculations within an APL document normally use the viewport width when defining resources that depend on the size of the viewport. Resource values are calculated when the document is first loaded, which happens before the final viewport output width has been calculated. Therefore, the default width of the viewport is a convenient baseline to calculate with.

The top-level component width minWidth, and maxWidth properties determine the top-level component output width and the viewport output width by the following rules:

The following rules use the top-level component properties for width, minWidth, and maxWidth to determine the output width of the component.

Component width is an absolute dimension

When the component width is an absolute dimension, the component output width is clamped to the component [minWidth, maxWidth] range. The viewport output width is the component output width clamped to the viewport [minWidth, maxWidth] range. Examples of absolute dimensions include values such as 25px, 10vw, or 30.

The following pseudo-code shows this calculation.

if TypeOf(component.width) == AbsoluteDimension:
  w = component.width
  w = Clamp( w, component.minWidth, component.maxWidth )
  component.output.width = w
  viewport.output.width = Clamp( w, viewport.minWidth, viewport.maxWidth )
  Layout( component, width=w )

For example:

Given  viewport:  { minWidth: 100, width: 200, maxWidth: 300       }
       component: { minWidth:   0, width: 250, maxWidth: Undefined }

Then   viewport.output.width  = 250
       component.output.width = 250

Component width is a relative dimension

When the component width is a relative dimension, the component output width is the product of the component width and the viewport width, clamped to the component [minWidth, maxWidth] range. The viewport output width is the viewport width.

The following pseudo-code shows this calculation.

if TypeOf(component.width) == RelativeDimension:
  w = component.width * viewport.width
  w = Clamp( w, component.minWidth, component.maxWidth )
  component.output.width = w
  viewport.output.width = viewport.width
  Layout( component, width=w )

For example:

Given  viewport:  { minWidth: 100, width:   200, maxWidth: 300 }
       component: { minWidth:   0, width: "80%", maxWidth: 150 }

Then   viewport.output.width  = 200
       component.output.width = 150

If you set the relative dimension smaller than 100%, the background shows on the right-hand side of the viewport. If you set the relative dimension larger than 100%, the right-hand side of the component is clipped.

If your goal is to stretch or shrink the viewport and the component by a percentage amount from the default viewport size, use an absolute dimension referencing the width of the viewport. For example, to make a component and viewport 25 percent larger than the default viewport width, set the component width to 125vw. That value is an absolute dimension equal to 125 percent of the viewport width and therefore follows the absolute dimension rules.

Component width is "auto"

If the component width is auto, the output width depends on whether the maxWidth has a value. If maxWidth has a value, the component tightly wraps its children and clamps to the component maxWidth and minWidth. If maxWidth doesn't have a value, the component fills the viewport.

If the component width is auto, the layout engine calculates an intermediate viewport output width for the component by laying out the component's internal elements using their "natural" width. That intermediate viewport output width is then clamped to both the component [minWidth, maxWidth] range and the viewport [minWidth, maxWidth] range. The component output width is set to the clamped value and the component is laid out a second time.

The following pseudo-code shows this calculation.

if TypeOf(component.width) == AutoDimension:
  w = Layout( component, width=Undefined ).getWidth()
  w = Clamp( w, component.minWidth, component.maxWidth )
  w = Clamp( w, viewport.minWidth, viewport.maxWidth )
  viewport.output.width = w
  Layout( component, width=w )

For example, assume that the top-level component is a Text component with a long paragraph of text.

Given  viewport:  { minWidth: 100, width:  200, maxWidth: 300 }
       component: { minWidth:   0, width: auto, maxWidth: Undefined }
       total text width (single line) = 430

Then   viewport.output.width  = 300
       component.output.width = 300

The auto setting for the component width property requires the layout algorithm to run twice. First, the component is laid out assuming its internal elements are their "natural" width. The natural width of a Text component is the width of the text laid out in a single line (in this example, 430). This width is then clamped to the valid width range specified by the viewport (in this example, 300). Finally, the component is laid out again with its width fixed to this value. This second layout pass wraps the text to multiple lines.

Component width and height are both "auto"

If the viewport is variable in both width and height and the top-level component has auto for both the width and height properties, APL uses the following algorithm.

if TypeOf(component.width) == AutoDimension AND TypeOf(component.height) == AutoDimension:
  // Calculate the width of the viewport
  w = Layout( component, width=Undefined, height=Undefined ).getWidth()
  w = Clamp( w, component.minWidth, component.maxWidth )
  w = Clamp( w, viewport.minWidth, viewport.maxWidth )
  viewport.output.width = w

  // Now calculate the height of the viewport
  h = Layout( component, width=w, height=Undefined ).getHeight()
  h = Clamp( h, component.minHeight, component.maxHeight )
  h = Clamp( h, viewport.minHeight, viewport.maxHeight )
  viewport.output.height = h

  // Layout with the final width and height
  Layout( component, width=w, height=h )

The first layout pass calculates the viewport output width. The second layout pass calculates the viewport output height. The final layout pass lays out the component hierarchy using the viewport output width and height.


Was this page helpful?

Last updated: Nov 28, 2023