HelixOverviewComponentsMapsGraphIntroductionInstallationDeriving a themeSandboxTheme builderVisual testingCortexDocsEngramBuildingTraceBuildingRecallDeclaredServicesInsightsGet in touchSource on GitHub
Loading the reference
Device ScreenView SourceEdit in SandboxView MarkdownCopy MarkdownOpen in ClaudeOpen in CursorA device's screen, drawn from a stream you supply, that sends taps, swipes, keys, and button presses back to the device.ExperimentalSince 0.211.0MediaUsageimport'@fusion.dev/helix/device-screen'import'@fusion.dev/helix-headless/device-screen'Preview
API ReferenceRoothelix-device-screenA device's screen, drawn from a stream you supply, that sends taps, swipes, keys, and button presses back to the device.
PropTypeDefaultDescriptionbackLabelstring"Back"The Back button's label.controlsstringWhich hardware buttons to draw, as a list: back, home, recents,
power, volume, rotate, screenshot, and fullscreen, or none.
They are drawn in that order whatever order the list is in. Absent is
home screenshot. volume draws Volume up and Volume down, and rotate
draws Rotate left and Rotate right.controlsLabelstring"Device controls"The name of the toolbar of hardware buttons, read by screen readers.controlsPlacement"bottom"|"end"|"start"|"top"Which side of the device the hardware buttons sit on. Absent and top
are a row above it, bottom is a row below it, and start and end are
a column beside it, as the Android Emulator draws its toolbar. The words
are sides, as Carousel's are, and not the corners a map's controls take.fallbackLabelstring"Device"The screen's name where label is empty and the host has no aria-label.forwardShortcutsbooleanfalseAlso sends key presses with Control, Command, or Alt held, which are left
to the browser otherwise. For an app that owns its window. Command or
Control with V pastes either way.fullscreenLabelstring"Fill the screen"The fullscreen button's label.homeLabelstring"Home"The Home button's label.keysHintLabelstring"Keys you press go to the device. Press Tab to leave the screen."What a screen reader says about the keys when it reaches the screen,
after its name.labelstring""The device's name, read by screen readers as the screen's name, such as
"iPhone 17 Pro". Name each device on a page with several. Required.loadingbooleanfalseShows the loading slot over the screen, for a stream that is starting
or has stopped. Screen readers hear loading-label.loadingLabelstring"Connecting to the device"What the screen shows and screen readers hear while loading is set and nothing is in the loading slot.powerLabelstring"Power"The Power button's label.readonlybooleanfalseShows the screen and sends nothing: no touches, scrolls, keys, or button
presses. The screen is then a picture, out of the tab order, and the
hardware buttons are off but for screenshot and fullscreen. Buttons of
your own in the controls slot are yours to turn off.recentsLabelstring"Recent apps"The Recent apps button's label.roleLabelstring"screen"What a screen reader calls the screen in place of its role, after its
name: "iPhone 17 Pro, screen". Empty leaves the role.rotateLeftLabelstring"Rotate left"The Rotate left button's label.rotateRightLabelstring"Rotate right"The Rotate right button's label.rotationnumber0How far to turn the picture clockwise, in degrees: 90, 180, or 270.
For a source that sends frames in the device's natural orientation while
the device is turned. Every point is turned back, so events stay in the
device's own orientation. A source whose frames turn with the device
needs none.screenHeightnumberThe screen's height in the units your device takes input in: points for
the iOS Simulator, pixels for an Android device. Set with screen-width.
Set alone, the width follows the stream's shape, and with neither, both
are the stream's own size in pixels.screenshotLabelstring"Take a screenshot"The screenshot button's label.screenWidthnumberThe screen's width in the units your device takes input in, as
screen-height is. Set alone, the height follows the stream's shape.separation"plain"How the device stands apart from the page. Absent draws its body around
the screen; plain draws the screen alone, with its rounded corners.shape"circle"|"square"The screen's outline. Absent is a rectangle with rounded corners;
square has square corners, as on a phone with a Home button or a
television, and circle is round, as on a round watch, and takes
touches inside the circle only.showTouchesbooleanfalseDraws a ring under each finger on the screen, as the iOS Simulator's
Show single touches does. Rings from showTap() and showSwipe() are
drawn either way.volumeDownLabelstring"Volume down"The Volume down button's label.volumeUpLabelstring"Volume up"The Volume up button's label.
ReadTypeDescriptionwhenSettledPromise<void>Resolves a frame after the first update, when transitions are switched on.
SlotDescription(default)The element that draws the stream: a <video>, an <img>, or a <canvas>.back-iconReplaces the glyph inside the Back button.bezelA picture of the device drawn over the screen, such as a photograph of a phone with a clear screen. It takes no touches.controlsButtons of your own, such as Shake or Record, in the row after the hardware buttons and before the fullscreen button.emptyContent shown over the screen while no element that draws the stream is inside and loading is not set, such as "No simulator is running" and a button to start one.footerContent below the device.fullscreen-iconReplaces the glyph inside the fullscreen button.headerContent above the device, such as its name and state.home-iconReplaces the glyph inside the Home button.loadingContent shown over the screen while loading is set, such as a spinner. loading-label by default, which screen readers hear either way.power-iconReplaces the glyph inside the Power button.recents-iconReplaces the glyph inside the Recent apps button.rotate-left-iconReplaces the glyph inside the Rotate left button.rotate-right-iconReplaces the glyph inside the Rotate right button.screenshot-iconReplaces the glyph inside the screenshot button.volume-down-iconReplaces the glyph inside the Volume down button.volume-up-iconReplaces the glyph inside the Volume up button.
EventTypeDescriptionhelix-device-buttonHelixDeviceButtonEventA hardware button was pressed, with how long it was held. Press it on the device in response.helix-device-keyHelixDeviceKeyEventA key went down or came up while the screen had focus. Press or release it on the device in response.helix-device-screenshotHelixDeviceScreenshotEventA screenshot was asked for. Take one in response.helix-device-scrollHelixDeviceScrollEventA wheel or a trackpad scrolled over the screen. Scroll the device in response.helix-device-swipeHelixDeviceSwipeEventOne finger moved across the screen and lifted. Swipe the device in response.helix-device-tapHelixDeviceTapEventOne finger touched the screen and lifted near where it landed. Tap the device in response.helix-device-textHelixDeviceTextEventText was pasted into the screen. Type it on the device in response.helix-device-touchHelixDeviceTouchEventA finger landed, moved, lifted, or was taken away. Touch the device in response.
MethodTypeDescriptioncapture(type: unknown, quality: number) => Promise<Blob>The picture on the screen now, as an image, at the stream's own size and
turned by rotation. For a page with no sharper screenshot from its
source.press(button: DeviceButton, duration: unknown) => voidPresses a hardware button, as its control does: sends
helix-device-button. duration is how long it is held, in
milliseconds.screenshot() => voidAsks for a screenshot, as the screenshot button does: sends helix-device-screenshot.showSwipe(fromX: number, fromY: number, toX: number, toY: number, duration: unknown) => voidDraws a ring that travels from one point to another over duration
milliseconds, in the device's units, for a swipe made elsewhere, as
showTap() does for a tap.showTap(x: number, y: number) => voidDraws a ring at a point on the screen for a moment, in the device's
units, for a touch made elsewhere, such as by an agent. Drawn whether or
not show-touches is set, and nothing is sent.
PartDescriptionbackThe Back button.back-buttonThe Back button's inner button.back-liveThe Back button's live region, which speaks while the button is pending.back-spinnerThe ring the Back button turns while it is pending.back-textThe box the Back button's icon sits in.bezelThe body of the device around the screen.controlsThe row of buttons: the hardware buttons and any of yours in the controls slot.deviceThe box the device is fitted into, which keeps its shape inside it.emptyThe box over the screen that holds the empty slot while no stream is inside and loading is not set. It stands beside the screen, so what you put in it takes presses and keys of its own, and a read-only screen does not hide it from screen readers.footerThe strip below the device.fullscreenThe button that makes the device fill the screen.fullscreen-buttonThe fullscreen button's inner button.fullscreen-liveThe fullscreen button's live region, which speaks while the button is pending.fullscreen-spinnerThe ring the fullscreen button turns while it is pending.fullscreen-textThe box the fullscreen button's icon sits in.headerThe strip above the device.homeThe Home button.home-buttonThe Home button's inner button.home-liveThe Home button's live region, which speaks while the button is pending.home-spinnerThe ring the Home button turns while it is pending.home-textThe box the Home button's icon sits in.keys-hintWhat a screen reader says about the keys when it reaches the screen, as its description. Read by screen readers only.liveWhat screen readers hear while loading is set: loading-label. Read by screen readers only.loadingThe box over the screen that holds the loading slot while loading is set. Screen readers hear live in its place.pictureThe box the stream is drawn in, turned by rotation.powerThe Power button.power-buttonThe Power button's inner button.power-liveThe Power button's live region, which speaks while the button is pending.power-spinnerThe ring the Power button turns while it is pending.power-textThe box the Power button's icon sits in.recentsThe Recent apps button.recents-buttonThe Recent apps button's inner button.recents-liveThe Recent apps button's live region, which speaks while the button is pending.recents-spinnerThe ring the Recent apps button turns while it is pending.recents-textThe box the Recent apps button's icon sits in.regionThe box that holds the device, its buttons, the header, and the footer.rotate-leftThe Rotate left button.rotate-left-buttonThe Rotate left button's inner button.rotate-left-liveThe Rotate left button's live region, which speaks while the button is pending.rotate-left-spinnerThe ring the Rotate left button turns while it is pending.rotate-left-textThe box the Rotate left button's icon sits in.rotate-rightThe Rotate right button.rotate-right-buttonThe Rotate right button's inner button.rotate-right-liveThe Rotate right button's live region, which speaks while the button is pending.rotate-right-spinnerThe ring the Rotate right button turns while it is pending.rotate-right-textThe box the Rotate right button's icon sits in.screenThe device's screen, which takes the touches and the keys.screenshotThe button that asks for a screenshot.screenshot-buttonThe screenshot button's inner button.screenshot-liveThe screenshot button's live region, which speaks while the button is pending.screenshot-spinnerThe ring the screenshot button turns while it is pending.screenshot-textThe box the screenshot button's icon sits in.touchA ring where a touch is or was.touch-heldA ring under a finger that is down, beside touch, with show-touches.volume-downThe Volume down button.volume-down-buttonThe Volume down button's inner button.volume-down-liveThe Volume down button's live region, which speaks while the button is pending.volume-down-spinnerThe ring the Volume down button turns while it is pending.volume-down-textThe box the Volume down button's icon sits in.volume-upThe Volume up button.volume-up-buttonThe Volume up button's inner button.volume-up-liveThe Volume up button's live region, which speaks while the button is pending.volume-up-spinnerThe ring the Volume up button turns while it is pending.volume-up-textThe box the Volume up button's icon sits in.
CSS PropertyDescription--device-screen-bezelHow thick the body is at the sides, as a fraction of the screen's width. 0.045 by default.--device-screen-bezel-blockHow thick the body is at the top and bottom, as a fraction of the screen's width. The same as --device-screen-bezel by default.--device-screen-bezel-colorThe color of the body around the screen.--device-screen-bezel-radiusThe body's corners, as a fraction of the screen's width. Round with the screen's corners by default.--device-screen-block-sizeThe element's height, which holds the device, its buttons, the header, and the footer. 36rem by default.--device-screen-radiusThe screen's corners, as a fraction of the screen's width. 0.13 by default, which is near a recent iPhone's.--device-screen-ratioThe drawn screen's width divided by its height, turned by rotation, as a number. Written by the frame once the screen's size is known.--device-screen-rotationHow far the picture is turned, as an angle. The frame writes it from rotation.--device-screen-touch-durationHow long a swipe's ring takes to travel, as a time. Written on each ring from showSwipe().--device-screen-touch-to-xWhere a swipe's ring travels to, across the screen, as a percentage. Written on each ring from showSwipe().--device-screen-touch-to-yWhere a swipe's ring travels to, down the screen, as a percentage. Written on each ring from showSwipe().--device-screen-touch-xWhere a ring is, across the screen, as a percentage. Written on each ring.--device-screen-touch-yWhere a ring is, down the screen, as a percentage. Written on each ring.
Custom stateDescriptionemptyNo element that draws the stream is inside, which the frame knows once it runs in the browser.fullscreenThe device fills the screen.loadingloading is set.readonlyreadonly is set, and the screen sends nothing.settledSet one frame after the first render. Transitions wait for it, so an element does not animate its own arrival.sidewaysrotation turns the picture a quarter, so the drawn screen is the device's height wide.touchingA finger is on the screen.
Roothelix-headless-device-screenA device's screen, drawn from a stream you supply, that sends taps, swipes, keys, and button presses back to the device.
PropTypeDefaultDescriptionbackLabelstring"Back"The Back button's label.controlsstringWhich hardware buttons to draw, as a list: back, home, recents,
power, volume, rotate, screenshot, and fullscreen, or none.
They are drawn in that order whatever order the list is in. Absent is
home screenshot. volume draws Volume up and Volume down, and rotate
draws Rotate left and Rotate right.controlsLabelstring"Device controls"The name of the toolbar of hardware buttons, read by screen readers.controlsPlacement"bottom"|"end"|"start"|"top"Which side of the device the hardware buttons sit on. Absent and top
are a row above it, bottom is a row below it, and start and end are
a column beside it, as the Android Emulator draws its toolbar. The words
are sides, as Carousel's are, and not the corners a map's controls take.fallbackLabelstring"Device"The screen's name where label is empty and the host has no aria-label.forwardShortcutsbooleanfalseAlso sends key presses with Control, Command, or Alt held, which are left
to the browser otherwise. For an app that owns its window. Command or
Control with V pastes either way.fullscreenLabelstring"Fill the screen"The fullscreen button's label.homeLabelstring"Home"The Home button's label.keysHintLabelstring"Keys you press go to the device. Press Tab to leave the screen."What a screen reader says about the keys when it reaches the screen,
after its name.labelstring""The device's name, read by screen readers as the screen's name, such as
"iPhone 17 Pro". Name each device on a page with several. Required.loadingbooleanfalseShows the loading slot over the screen, for a stream that is starting
or has stopped. Screen readers hear loading-label.loadingLabelstring"Connecting to the device"What the screen shows and screen readers hear while loading is set and nothing is in the loading slot.powerLabelstring"Power"The Power button's label.readonlybooleanfalseShows the screen and sends nothing: no touches, scrolls, keys, or button
presses. The screen is then a picture, out of the tab order, and the
hardware buttons are off but for screenshot and fullscreen. Buttons of
your own in the controls slot are yours to turn off.recentsLabelstring"Recent apps"The Recent apps button's label.roleLabelstring"screen"What a screen reader calls the screen in place of its role, after its
name: "iPhone 17 Pro, screen". Empty leaves the role.rotateLeftLabelstring"Rotate left"The Rotate left button's label.rotateRightLabelstring"Rotate right"The Rotate right button's label.rotationnumber0How far to turn the picture clockwise, in degrees: 90, 180, or 270.
For a source that sends frames in the device's natural orientation while
the device is turned. Every point is turned back, so events stay in the
device's own orientation. A source whose frames turn with the device
needs none.screenHeightnumberThe screen's height in the units your device takes input in: points for
the iOS Simulator, pixels for an Android device. Set with screen-width.
Set alone, the width follows the stream's shape, and with neither, both
are the stream's own size in pixels.screenshotLabelstring"Take a screenshot"The screenshot button's label.screenWidthnumberThe screen's width in the units your device takes input in, as
screen-height is. Set alone, the height follows the stream's shape.shape"circle"|"square"The screen's outline. Absent is a rectangle with rounded corners;
square has square corners, as on a phone with a Home button or a
television, and circle is round, as on a round watch, and takes
touches inside the circle only.showTouchesbooleanfalseDraws a ring under each finger on the screen, as the iOS Simulator's
Show single touches does. Rings from showTap() and showSwipe() are
drawn either way.volumeDownLabelstring"Volume down"The Volume down button's label.volumeUpLabelstring"Volume up"The Volume up button's label.
ReadTypeDescriptionwhenSettledPromise<void>Resolves a frame after the first update, when transitions are switched on.
SlotDescription(default)The element that draws the stream: a <video>, an <img>, or a <canvas>.back-iconReplaces the glyph inside the Back button.bezelA picture of the device drawn over the screen, such as a photograph of a phone with a clear screen. It takes no touches.controlsButtons of your own, such as Shake or Record, in the row after the hardware buttons and before the fullscreen button.emptyContent shown over the screen while no element that draws the stream is inside and loading is not set, such as "No simulator is running" and a button to start one.footerContent below the device.fullscreen-iconReplaces the glyph inside the fullscreen button.headerContent above the device, such as its name and state.home-iconReplaces the glyph inside the Home button.loadingContent shown over the screen while loading is set, such as a spinner. loading-label by default, which screen readers hear either way.power-iconReplaces the glyph inside the Power button.recents-iconReplaces the glyph inside the Recent apps button.rotate-left-iconReplaces the glyph inside the Rotate left button.rotate-right-iconReplaces the glyph inside the Rotate right button.screenshot-iconReplaces the glyph inside the screenshot button.volume-down-iconReplaces the glyph inside the Volume down button.volume-up-iconReplaces the glyph inside the Volume up button.
EventTypeDescriptionhelix-device-buttonHelixDeviceButtonEventA hardware button was pressed, with how long it was held. Press it on the device in response.helix-device-keyHelixDeviceKeyEventA key went down or came up while the screen had focus. Press or release it on the device in response.helix-device-screenshotHelixDeviceScreenshotEventA screenshot was asked for. Take one in response.helix-device-scrollHelixDeviceScrollEventA wheel or a trackpad scrolled over the screen. Scroll the device in response.helix-device-swipeHelixDeviceSwipeEventOne finger moved across the screen and lifted. Swipe the device in response.helix-device-tapHelixDeviceTapEventOne finger touched the screen and lifted near where it landed. Tap the device in response.helix-device-textHelixDeviceTextEventText was pasted into the screen. Type it on the device in response.helix-device-touchHelixDeviceTouchEventA finger landed, moved, lifted, or was taken away. Touch the device in response.
MethodTypeDescriptioncapture(type: unknown, quality: number) => Promise<Blob>The picture on the screen now, as an image, at the stream's own size and
turned by rotation. For a page with no sharper screenshot from its
source.press(button: DeviceButton, duration: unknown) => voidPresses a hardware button, as its control does: sends
helix-device-button. duration is how long it is held, in
milliseconds.screenshot() => voidAsks for a screenshot, as the screenshot button does: sends helix-device-screenshot.showSwipe(fromX: number, fromY: number, toX: number, toY: number, duration: unknown) => voidDraws a ring that travels from one point to another over duration
milliseconds, in the device's units, for a swipe made elsewhere, as
showTap() does for a tap.showTap(x: number, y: number) => voidDraws a ring at a point on the screen for a moment, in the device's
units, for a touch made elsewhere, such as by an agent. Drawn whether or
not show-touches is set, and nothing is sent.
PartDescriptionbackThe Back button.back-buttonThe Back button's inner button.back-liveThe Back button's live region, which speaks while the button is pending.back-spinnerThe ring the Back button turns while it is pending.back-textThe box the Back button's icon sits in.bezelThe body of the device around the screen.controlsThe row of buttons: the hardware buttons and any of yours in the controls slot.deviceThe box the device is fitted into, which keeps its shape inside it.emptyThe box over the screen that holds the empty slot while no stream is inside and loading is not set. It stands beside the screen, so what you put in it takes presses and keys of its own, and a read-only screen does not hide it from screen readers.footerThe strip below the device.fullscreenThe button that makes the device fill the screen.fullscreen-buttonThe fullscreen button's inner button.fullscreen-liveThe fullscreen button's live region, which speaks while the button is pending.fullscreen-spinnerThe ring the fullscreen button turns while it is pending.fullscreen-textThe box the fullscreen button's icon sits in.headerThe strip above the device.homeThe Home button.home-buttonThe Home button's inner button.home-liveThe Home button's live region, which speaks while the button is pending.home-spinnerThe ring the Home button turns while it is pending.home-textThe box the Home button's icon sits in.keys-hintWhat a screen reader says about the keys when it reaches the screen, as its description. Read by screen readers only.liveWhat screen readers hear while loading is set: loading-label. Read by screen readers only.loadingThe box over the screen that holds the loading slot while loading is set. Screen readers hear live in its place.pictureThe box the stream is drawn in, turned by rotation.powerThe Power button.power-buttonThe Power button's inner button.power-liveThe Power button's live region, which speaks while the button is pending.power-spinnerThe ring the Power button turns while it is pending.power-textThe box the Power button's icon sits in.recentsThe Recent apps button.recents-buttonThe Recent apps button's inner button.recents-liveThe Recent apps button's live region, which speaks while the button is pending.recents-spinnerThe ring the Recent apps button turns while it is pending.recents-textThe box the Recent apps button's icon sits in.regionThe box that holds the device, its buttons, the header, and the footer.rotate-leftThe Rotate left button.rotate-left-buttonThe Rotate left button's inner button.rotate-left-liveThe Rotate left button's live region, which speaks while the button is pending.rotate-left-spinnerThe ring the Rotate left button turns while it is pending.rotate-left-textThe box the Rotate left button's icon sits in.rotate-rightThe Rotate right button.rotate-right-buttonThe Rotate right button's inner button.rotate-right-liveThe Rotate right button's live region, which speaks while the button is pending.rotate-right-spinnerThe ring the Rotate right button turns while it is pending.rotate-right-textThe box the Rotate right button's icon sits in.screenThe device's screen, which takes the touches and the keys.screenshotThe button that asks for a screenshot.screenshot-buttonThe screenshot button's inner button.screenshot-liveThe screenshot button's live region, which speaks while the button is pending.screenshot-spinnerThe ring the screenshot button turns while it is pending.screenshot-textThe box the screenshot button's icon sits in.touchA ring where a touch is or was.touch-heldA ring under a finger that is down, beside touch, with show-touches.volume-downThe Volume down button.volume-down-buttonThe Volume down button's inner button.volume-down-liveThe Volume down button's live region, which speaks while the button is pending.volume-down-spinnerThe ring the Volume down button turns while it is pending.volume-down-textThe box the Volume down button's icon sits in.volume-upThe Volume up button.volume-up-buttonThe Volume up button's inner button.volume-up-liveThe Volume up button's live region, which speaks while the button is pending.volume-up-spinnerThe ring the Volume up button turns while it is pending.volume-up-textThe box the Volume up button's icon sits in.
CSS PropertyDescription--device-screen-ratioThe drawn screen's width divided by its height, turned by rotation, as a number. Written by the frame once the screen's size is known.--device-screen-rotationHow far the picture is turned, as an angle. The frame writes it from rotation.--device-screen-touch-durationHow long a swipe's ring takes to travel, as a time. Written on each ring from showSwipe().--device-screen-touch-to-xWhere a swipe's ring travels to, across the screen, as a percentage. Written on each ring from showSwipe().--device-screen-touch-to-yWhere a swipe's ring travels to, down the screen, as a percentage. Written on each ring from showSwipe().--device-screen-touch-xWhere a ring is, across the screen, as a percentage. Written on each ring.--device-screen-touch-yWhere a ring is, down the screen, as a percentage. Written on each ring.
Custom stateDescriptionemptyNo element that draws the stream is inside, which the frame knows once it runs in the browser.fullscreenThe device fills the screen.loadingloading is set.readonlyreadonly is set, and the screen sends nothing.settledSet one frame after the first render. Transitions wait for it, so an element does not animate its own arrival.sidewaysrotation turns the picture a quarter, so the drawn screen is the device's height wide.touchingA finger is on the screen.
ExamplesNameDescriptionAgentA screen an agent is driving: it takes no input, and marks each touch the agent makes.AndroidAn Android phone with its navigation and hardware buttons in a column beside it.BezelsThree bodies: a phone with a Home button, a round watch, and a tablet on its side.Custom ControlsButtons of your own in the row beside the hardware buttons.EmptyThe screen while no device is running, with words of your own on it.EventsAnswering taps, swipes, keys, and buttons, and marking each tap where it landed.LoadingThe screen while its stream connects.PreviewA phone's screen from a stream, with its Home and screenshot buttons.PreviewA phone's screen from a stream, with its Home and screenshot buttons.