Showcase app: AI reference map
Reference map of reusable components, patterns, contexts, and utilities in the Showcase app
Purpose: This document is a structured reference for AI assistants working on the Showcase app. It maps reusable components, architectural patterns, contexts, and utilities to their source files and usage examples. You can use this document to find existing code instead of writing new implementations.
All paths are relative to the repository root.
Table of contents
The following list links to each section of this reference.
- App shell and navigation
- Context providers (state management)
- Reusable UI components
- Showcase utilities and data
- Drawing styles and theming
- Architectural patterns
- Dialog patterns
- List and grid scene patterns
- Media playback patterns
- Compiled (BRS/XML) components
1. App shell and navigation
These components provide the app shell and navigation.
ShowcaseApp (root component)
The root entry point of the app is ShowcaseApp.
- Name:
ShowcaseApp - When to use: The root entry point of the entire app. When you need to understand the provider hierarchy or add a new global provider, start here. Extends
FocusBoundaryBaseand wraps the provider tree inRootFocusBoundary(bridge fields:keyEvent,focusActive,handledKeys,focusPath). Provider hierarchy:RootFocusBoundary→ResolutionProvider→ScreenRegistryProvider(which mountsScreenControllerProviderinternally) →MenuPathControllerProvider→FullscreenVideoProvider→DialogProvider. - Implementation file:
examples/showcase/src/components/showcase-app.tsx - Usage example:
examples/showcase/src/index.ts(registers ShowcaseApp viadeclareTsComponent) - Focus reference:
examples/focus-boundary/src/components/focus-boundary-app.tsx
MainScene (scene & dialog registry)
The MainScene component registers every scene and dialog factory.
- Name:
MainScene - When to use: When registering a new scene or dialog. All scene factories and dialog factories are registered here in
SCENESandDIALOGSarrays. This is the single place where scene IDs are mapped to components. - Implementation file:
examples/showcase/src/components/main-scene.tsx - Usage example:
examples/showcase/src/components/showcase-app.tsx(rendered inside provider tree)
MenuScene (fallback / home screen)
The home screen of the app is MenuScene.
- Name:
MenuScene - When to use: When
setScreen(null)is called or no scene is active. This is the home screen. It renders theMainMenuinside aPanelSetwrapped bySceneWrapper, inside a nestedFocusBoundarythat handles app-level Back (exit dialog) viaonUnhandledKey. You must not threadFocusBoundarythrough PanelSet andListPanelslides; panel menus stay on SceneGraph-native focus (LabelList,jumpTo,slidingBack). - Implementation file:
examples/showcase/src/components/menu-scene.tsx - Usage example:
examples/showcase/src/components/showcase-app.tsx(passed asfallbacktoScreenRegistryProvider)
MainMenu (top-level menu)
The root menu that the app renders inside MenuScene is MainMenu.
- Name:
MainMenu - When to use: When adding a new top-level showcase entry. Each item defines a
title, optionalsceneDialogId, and agetNextPanelfactory for the info panel or submenu. The Keyboards entry opensKeyboardShowcase, whose items open fullscreen scenes for DynamicCustomKeyboard,DynamicKeyGrid,DynamicKeyboard,DynamicMiniKeyboard,National CustomKeyboard, andDynamicPinPad. - Implementation file:
examples/showcase/src/components/main-menu.tsx - Usage example:
examples/showcase/src/components/menu-scene.tsx(rendered inside PanelSet) - Usage example:
examples/showcase/src/components/showcases/keyboard-showcase/index.tsx(extensible keyboard submenu)
SceneWrapper / BackSceneWrapper / SceneFocusBoundary
The SceneWrapper, BackSceneWrapper, and SceneFocusBoundary components provide the standard chrome and focus handling for fullscreen views.
- Name:
SceneWrapper,BackSceneWrapper,SceneFocusBoundary - When to use: When you need a fullscreen view with the standard Roku Overhang chrome (logo, clock, title, optional options text).
SceneWrapperrenders the Overhang header and passes children through.BackSceneWrapperwrapsSceneWrapperinSceneFocusBoundary, which registers the active scene as the nested child ofRootFocusBoundaryviaACTIVE_REGION_REFand handles keys throughonUnhandledKey(default:back→setScreen(null)). You can pass extra scene keys onBackSceneWrapperviaonUnhandledKey(for example,options,OK,left/right). Props:title,showOptions,optionsText,showBackHint,onBack,onUnhandledKey,children. Every fullscreen scene must be wrapped inBackSceneWrapper. - Implementation file:
examples/showcase/src/components/scene-wrapper.tsx,scene-focus-boundary.tsx - Usage example:
examples/showcase/src/components/showcases/poster-showcase/poster-scene-showcase.tsx(BackSceneWrapper with title + showBackHint) - Usage example:
examples/showcase/src/components/showcases/busy-spinner-showcase/busy-spinner-scene-showcase.tsx(onUnhandledKey={{ OK: onPress(toggle) }})
Focus region refs (ACTIVE_REGION_REF / REGION_SHELL_REF)
- Name:
ACTIVE_REGION_REF,REGION_SHELL_REF,RegionShellFocusable - When to use:
ACTIVE_REGION_REFis the shared stable identity wired asinitialFocusonRootFocusBoundaryandfocusIdon each menu/scene nestedFocusBoundary. Only one region is mounted at a time (menu or fullscreen scene).REGION_SHELL_REF+RegionShellFocusableprovide a no-op virtual focus target inside SceneGraph-native regions so thatonUnhandledKeycan dispatch (PanelSet, RowList, and so on keep SceneGraph focus). - Implementation file:
examples/showcase/src/components/focus-region-context.tsx,region-shell-focusable.tsx
SceneDialogMenu
The SceneDialogMenu component is a labeled list menu that can open scenes and dialogs.
- Name:
SceneDialogMenu - When to use: When you need a labeled list menu that can trigger both scene navigation and dialog opening. Wraps
ListMenuPaneland addsScreenRegistryContext+DialogContextintegration: items withsceneDialogIdswitch scenes viasetScreen, items withisDialog: trueopen dialogs viasetDialog. UsesMenuPathControllerContext(jumpTo,saveMenuPath) for cursor restoration after Back; it does not use an imperativepanelRef.focus(). Props:items(array ofIListMenuPanelItem),slidingBack,panelSize,leftOnly,onItemSelected. You can use this instead ofListMenuPanelwhen items need to open scenes or dialogs. - Implementation file:
examples/showcase/src/components/scene-dialog-menu.tsx - Usage example:
examples/showcase/src/components/showcases/dialog-showcases/index.tsx(DialogShowcase menu) - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/index.tsx(ListAndGridShowcase menu) - Usage example:
examples/showcase/src/components/showcases/keyboard-showcase/index.tsx(KeyboardShowcase menu)
ListMenuPanel
The ListMenuPanel component is a labeled list with drill-down panel navigation.
- Name:
ListMenuPanel - When to use: When you need a labeled list with drill-down panel navigation. Structurally it is a ListPanel containing a LabelList built from
ContentNodechildren. When an item is focused, itsgetNextPanelfactory is called to render the adjacent detail panel. SupportsjumpTofor restoring focus position,hasNextPaneloverride, an optional info message Poster at the bottom, and callbacks foronItemFocused,onItemSelected,onFocusedChild. Props:items(array ofIListMenuPanelItem),slidingBack,panelSize,leftOnly,gainFocus,messageText, and so on. You can use it for panel-only navigation menus (no scene/dialog switching). - Implementation file:
examples/showcase/src/components/list-menu-panel.tsx - Usage example:
examples/showcase/src/components/showcases/label-showcases/index.tsx(LabelShowcase submenu) - Usage example:
examples/showcase/src/components/showcases/group-submenu.tsx(GroupSubmenu)
2. Context providers (state management)
These contexts and providers manage navigation, dialogs, and fullscreen video.
ScreenRegistryContext / ScreenRegistryProvider (app-level, id-based)
The ScreenRegistryContext context navigates screens by string ID.
- Name:
ScreenRegistryContext - When to use: Default choice for any showcase code that wants to address screens by string id. The provider holds a
Map<string, () => JSX.Element>of screen factories and resolves ids before delegating to the underlyingScreenControllerContext. Mounted once at the app root (ScreenRegistryProvider); internally mounts aScreenControllerProviderso the lower-level controller is also available throughout the tree. Key API:registerScreen(id, factory)/deregisterScreen(id): add/remove screens (call inonMount/onCleanup).setScreen(id | null)/pushScreen(id | null)/resetScreen(id | null): id-based navigation; unknown ornullids render the fallback.popScreen(),getScreen(),onScreenCovered,onScreenUncovered: pass through to the underlying controller.
- Implementation file:
examples/showcase/src/components/screen-registry/screen-registry.tsx - Usage example:
examples/showcase/src/components/scene-wrapper.tsx(BackSceneWrappercallssetScreen(null)on Back key) - Usage example:
examples/showcase/src/components/scene-dialog-menu.tsx(callssetScreenon item selection)
ScreenControllerContext / ScreenControllerProvider (lower-level, factory-based)
The ScreenControllerContext context navigates screens by factory function.
- Name:
ScreenControllerContext - When to use: When you want to push/replace screens directly with factory functions (no string ids). Available throughout the showcase tree because
ScreenRegistryProvidermounts aScreenControllerProviderinternally. You canuseContext(ScreenControllerContext)anywhere. The screen-stack showcase uses this directly to push the next screen as a JSX factory; most other showcases prefer the higher-levelScreenRegistryContext. Key API:pushScreen(factory | null)/setScreen(factory | null)/resetScreen(factory? | null):null(or omitted onresetScreen) renders the provider's fallback.popScreen(),getScreen(),onScreenCovered,onScreenUncovered.
- Implementation file:
packages/navigation/src/screen-controller/screen-controller.tsx(imported as@roku-sdk/navigation) - Usage example:
examples/showcase/src/components/showcases/screen-stack-showcase/screen-stack-base-scene.tsx(pushScreen(() => <ScreenStack1 />)on OK)
MenuPathControllerContext / MenuPathControllerProvider
The MenuPathControllerContext context saves and restores nested menu focus positions.
- Name:
MenuPathControllerContext - When to use: When a menu component needs to save and restore nested focus positions across scene transitions. The provider owns a
createSignal<number[]>for the focused index path and an internal depth counter. Key API:acquireMenuDepth()/releaseMenuDepth(): manages a nesting depth counter; each mounted menu claims one slot.trackMenuFocus(depth, index): record the focused item index at a given nesting depth; truncates deeper entries when focus diverges.saveMenuPath(): snapshot the current focus path into the menu index stack so it can be restored later.getMenuIndexStack()/setMenuIndexStack(...): direct access to the saved index stack used by restorers.
- Implementation file:
examples/showcase/src/components/menu-path-controller-context.tsx - Usage example:
examples/showcase/src/components/scene-dialog-menu.tsx(SceneDialogMenutracks focus and restores it on back navigation)
DialogContext / DialogProvider
The DialogContext context manages modal dialogs.
- Name:
DialogContext - When to use: When you need a registry-based modal dialog manager with stack-based parent/child navigation. The provider holds a
Map<string, (data?) => JSX.Element>of dialog factories and a signal-based dialog state stack. Key API:registerDialog(id, factory)/deregisterDialog(id): add/remove dialog types (call inonMount/onCleanup).setDialog(id, onClose, data?, parentId?): open a dialog by ID;onCloseis called when the dialog reports completion.closeDialog(params?): close the current dialog. If it is a child, restores the parent with_childCloseParamsmerged into its data. If root, callsonCloseand clears.openChildDialog(childId, childData, parentData): pushes a child dialog onto the stack; parent data is backed up and restored when child closes.getDialogElement(): returns the current dialog JSX or null.getDialogData<T>()/getParentDialogData<T>(): typed accessors for current/parent dialog data.getChildCloseParams<T>(data): utility to extract_childCloseParamsfrom data after a child closes.
- Implementation file:
examples/showcase/src/components/showcases/dialog-showcases/dialog-context.tsx - Usage example:
examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx(usescloseDialoginonWasClosed) - Usage example:
examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx(usesopenChildDialogfor nested navigation)
FullscreenVideoContext / FullscreenVideoProvider
The FullscreenVideoContext context coordinates scene transitions to and from the fullscreen video player.
- Name:
FullscreenVideoContext - When to use: When you need to coordinate a scene transition to/from a fullscreen video player. The provider wraps
ScreenRegistryContext.setScreenwith video-specific state: aparamssignal (IFullscreenVideoParams: playlist, contentIndex, seekPosition) and areturnToScenesignal. Key API:openFullscreenVideo(params, returnToScene?): stores playback params, then callssetScreen("fullscreen-video-scene").closeFullscreenVideo(): clears params, then callssetScreen(returnToScene)to navigate back.getParams(): reactive accessor for the current playback params (null when inactive).
- Implementation file:
examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-context.tsx - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/time-grid-video-preview.tsx(opens fullscreen on program selection)
3. Reusable UI components
These components are reusable across showcases.
InfoPanel
The InfoPanel component is a titled rich-text panel with automatic overflow handling.
- Name:
InfoPanel - When to use: When you need a titled rich-text panel with automatic overflow handling. Structurally it is a Panel containing a Label title and a
MultiStyleLabelbody wrapped in aMaskGroup. It measures body content on mount viaBoundingTracker: if text fits, it renders statically; if it overflows, it applies a gradient mask and a looping scrollAnimationwithVector2DFieldInterpolator. Supports configurablepanelSize, customdrawingStyles, and an optional "Press OK" call-to-action banner. Props:id,title,text,panelSize,drawingStyles,showOkMessage. The standard descriptive panel for all scene showcases, and reusable for any scrollable rich-text display. - Implementation file:
examples/showcase/src/components/info-panel/info-panel.tsx - Usage example:
examples/showcase/src/components/showcases/poster-showcase/poster-showcase.tsx(PosterPanel: narrow, with showOkMessage) - Usage example:
examples/showcase/src/components/showcases/animation-showcase/animation-info-panel.tsx(AnimationInfoPanel: narrow, with showOkMessage) - Usage example:
examples/showcase/src/components/showcases/dialog-showcases/simple-dialog-panel.tsx(SimpleDialogPanel: medium, with showOkMessage)
CodePanel
The CodePanel component renders text on a Poster background with a custom font.
- Name:
CodePanel - When to use: When you need a text block rendered on a Poster background with a custom font. Structurally it is a Poster (9-patch bitmap background) containing a Label with the Inconsolata monospaced font, padded content area, and configurable dimensions. Accepts
translation,width,height, andtextprops. Used in list and grid scenes for live code snippets, and suitable for any styled text overlay on a poster background. - Implementation file:
examples/showcase/src/components/code-panel.tsx - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx(reactive text on poster background showing current PosterGrid props)
TbdPanel
The TbdPanel component is a minimal placeholder panel with a styled message.
- Name:
TbdPanel - When to use: When you need a minimal placeholder panel with a styled message. Structurally it is a non-focusable Panel with a MultiStyleLabel that interpolates a component name into a template string. Props:
componentName. Used as a stand-in when a showcase has not been implemented. - Implementation file:
examples/showcase/src/components/tbd-panel.tsx - Usage example: Reference the implementation for the pattern.
Boundary
The Boundary component is a container that sizes itself to its children.
- Name:
Boundary - When to use: When you need a container that auto-sizes to its children with a visible border. Structurally it is a
Rectanglewhose dimensions are set dynamically: on mount it triggers aBoundingTrackermeasurement of its children, then sets the Rectangle width/height to the measured bounds plus configurable padding. The background is a semi-transparent white (#FFFFFF11). Children are arranged inside a verticalLayoutGroup. Props:children,padding(defaults to 5). It measures only once on mount; therefore, children must be static. - Implementation file:
examples/showcase/src/components/showcases/common/boundary.tsx - Usage example:
examples/showcase/src/components/showcases/label-showcases/label-showcase-panel.tsx(wraps Label examples to visualize bounding areas)
PropertyChooserDialog
The PropertyChooserDialog component is a data-driven dialog for selecting property values.
- Name:
PropertyChooserDialog - When to use: When you need a data-driven dialog for selecting values from a set of named properties. Structurally it is a
StandardDialogthat renders a list ofStdDlgActionCardItementries from anIPropertyDef[]array: boolean properties render as toggleable checkboxes, non-boolean properties show a "more info" icon and drill down toPropertyValueDialog(child dialog navigation). Returns the edited property set viaDialogCloseParamson Apply. Driven entirely by data; no hardcoded fields. Used for runtime component property editing in showcase scenes. - Implementation file:
examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx(opens via Options key to configure PosterGrid props)
PropertyValueDialog
The PropertyValueDialog component is a single-select radio-button list dialog.
- Name:
PropertyValueDialog - When to use: When you need a single-select radio-button list dialog for choosing one value from a set of options. Structurally it is a StandardDialog with
StdDlgItemGroupcontaining StdDlgActionCardItem entries withradiobuttonicons. ReceivesIPropertyValueData(property name, label, options, selected index) and returns the selected index on close. Designed as a child dialog opened fromPropertyChooserDialog, but the pattern is reusable for any single-select picker. - Implementation file:
examples/showcase/src/components/property-chooser/property-value-dialog.tsx - Usage example:
examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx(opens viaopenChildDialog)
ItemSelectedDialog
The ItemSelectedDialog component is a one-message, one-button dialog.
- Name:
ItemSelectedDialog - When to use: When you need a one-message, one-button dialog. Structurally it is a
StandardMessageDialogthat receives amessagestring viaIItemSelectedDataand renders it with a single "OK" button. Follows the standard dialog close lifecycle. A generic notification/confirmation dialog; pass any message string. Used across list and grid showcases on item selection. - Implementation file:
examples/showcase/src/components/showcases/list-and-grid-showcase/item-selected-dialog.tsx - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx(opened on OK key press in PosterGrid)
DialogPalette
The DialogPalette component provides a predefined color palette for dialog theming.
- Name:
DialogPalette - When to use: When you need a pre-defined color palette for dialog theming. Structurally it is a thin wrapper that renders
<rsgPalette colors={dialogPaletteColors} />. ThedialogPaletteColorsobject defines color keys:dialogBackgroundColor,dialogItemColor,dialogTextColor,dialogFocusColor,dialogFocusItemColor,dialogSecondaryTextColor,dialogSecondaryItemColor,dialogFootprintColor. You can pass it as thepaletteprop on any StandardDialog or variant. - Implementation file:
examples/showcase/src/components/showcases/dialog-showcases/dialog-palette.tsx - Usage example:
examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx(passed aspalette={<DialogPalette />})
4. Showcase utilities and data
These utilities and data helpers support the showcases.
Showcase-utils (scene helper functions)
These functions support interactive scene showcases.
- Name:
openPropertyChooser,focusLabelText,makeCodeText,makeOptionsKeyHandler,makeOptionsUnhandledKey,HELP_STYLES - When to use: Collection of reusable functions for interactive scene showcases:
openPropertyChooser(setDialog, title, config, propsState, setPropsState, defaultProps): opens the PropertyChooserDialog, applies results to a signal on close. Handles the full dialog lifecycle.focusLabelText(index, itemText): returns a formatted string like"Focused: #3 - Drama"or"Focused: (none)". Generic index+label formatter.makeCodeText(componentName, id, config, propsState, extraLines?): returns a reactive accessor() => stringthat generates a JSX-like snippet with current property values. Any component, any props.makeOptionsKeyHandler(onOptionsKey): legacyEventHandlerKeycallback for the Options (*) key (you can usemakeOptionsUnhandledKeywithBackSceneWrapperinstead).makeOptionsUnhandledKey(onOptionsKey): returns anonPresshandler forBackSceneWrapper/FocusBoundaryonUnhandledKey.options.HELP_STYLES:DrawingStylemap with akeytag (bold yellow) for highlighting remote-key names in help text.
- Implementation file:
examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.ts - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx(uses all five exports)
Property chooser types
These types define the property configuration for the property chooser.
- Name:
IPropertyConfig,IPropertyDef,IPropertyOption,PropertyValue,IPropertyChooserData - When to use: When defining the property configuration for a showcase that uses the PropertyChooserDialog.
IPropertyConfigdefines available options for each property.IPropertyDefadds the current selection. - Implementation file:
examples/showcase/src/components/property-chooser/property-chooser-types.ts - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx(POSTER_GRID_PROPERTY_CONFIG array)
Property chooser utils
These helpers connect the property chooser to scene showcases.
- Name:
applyPropertiesFromDialog,buildPropertiesFromConfig,formatPropertiesAsText,getPropertyValueText,propertyValuesEqual - When to use: When integrating the PropertyChooserDialog with a scene showcase.
buildPropertiesFromConfigconverts config + current state into dialog data.applyPropertiesFromDialogmerges dialog results back.formatPropertiesAsTextgenerates the code-panel text. - Implementation file:
examples/showcase/src/components/property-chooser/property-chooser-utils.ts - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.ts(used byopenPropertyChooserandmakeCodeText)
Picsum image utils
The getImage function builds a remote image URL at a specific pixel size.
- Name:
getImage - When to use: When you need a remote image URL at a specific pixel size.
getImage(width, height, seed)returns an S3-hosted JPEG URL. Theseedparameter (0-based) selects different images. You can use it whenever a Poster, grid item, or any image-bearing component needs a remote image source at exact dimensions. - Implementation file:
examples/showcase/src/components/showcases/showcase-utils/picsum-utils.ts - Usage example:
examples/showcase/src/components/showcases/poster-showcase/poster-scene-showcase.tsx(poster images at various sizes) - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx(grid item images with reactive sizing)
Video playlist
Video playlistThe getVideoPlaylist function returns a list of video items.
- Name:
getVideoPlaylist,IPlaylistItem - When to use: When you need an array of
{ url, title }objects for video playback.getVideoPlaylist()returns a static list loaded from a JSON file (MP4 URLs).IPlaylistItemis the shared type. You can use it with the Video component'scontentIsPlaylistmode or any component that needs a media item list. - Implementation file:
examples/showcase/src/components/showcases/showcase-utils/video-playlist.ts - Data file:
examples/showcase/src/components/showcases/showcase-utils/video-playlist.json - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/time-grid-video-preview.tsx
Audio playlist
Audio playlistThe getAudioPlaylist function returns a list of audio items.
- Name:
getAudioPlaylist - When to use: When you need an array of
{ url, title }objects for audio playback.getAudioPlaylist()returns a static list loaded from a JSON file (MP3 URLs). Uses the sameIPlaylistItemtype as the video playlist. - Implementation file:
examples/showcase/src/components/showcases/showcase-utils/audio-playlist.ts - Data file:
examples/showcase/src/components/showcases/showcase-utils/audio-playlist.json - Usage example:
examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx
5. Drawing styles and theming
These style maps and palettes define text and dialog theming.
DRAWING_STYLES / RICH_DRAWING_STYLES
These maps define reusable text styles for MultiStyleLabel.
- Name:
DRAWING_STYLES,RICH_DRAWING_STYLES,OK_MESSAGE_STYLES - When to use: When you need pre-defined
DrawingStylemaps for MultiStyleLabel. These are reusable tag-to-style dictionaries:DRAWING_STYLES:titleisSystemFont.MediumBold, white.RICH_DRAWING_STYLES: extendsDRAWING_STYLESwithh3(large bold),h4(medium bold),b(small bold),code(small bold, light blue#AAD4FF).OK_MESSAGE_STYLES:okisSystemFont.MediumBold, yellow.
Pass any of these (or your own{ [tag]: DrawingStyle }map) as thedrawingStylesprop on MultiStyleLabel orInfoPanel.
- Implementation file:
examples/showcase/src/components/drawing-styles.ts - Re-export file:
examples/showcase/src/components/info-panel/drawing-styles.ts - Usage example:
examples/showcase/src/components/info-panel/info-panel.tsx(defaultdrawingStylesfor body text)
Dialog palette colors
The dialogPaletteColors object and the DialogPalette component define the shared dialog color scheme.
- Name:
dialogPaletteColors,DialogPalette - When to use: When you need the shared color scheme for
RsgPalette-based dialog theming.dialogPaletteColorsis a plain object with eight color keys (background, item, text, focus, focus-item, secondary-text, secondary-item, footprint).DialogPaletteis a component that renders<rsgPalette colors={dialogPaletteColors} />. Either export the object directly for custom palette composition, or use the component aspalette={<DialogPalette />}. - Implementation file:
examples/showcase/src/components/showcases/dialog-showcases/dialog-palette.tsx - Usage example:
examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx
HELP_STYLES
The HELP_STYLES map highlights remote-key names in help text.
- Name:
HELP_STYLES - When to use: When you need a
DrawingStylemap that highlights a<key>tag in bold yellow. A single-tag style dictionary:{ key: { fontUri: SystemFont.SmallBold, color: "#FFFF00FF" } }. You can pass it asdrawingStylesto any MultiStyleLabel where you want<key>Options (*)</key>to render highlighted. - Implementation file:
examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.ts - Usage example: Various scene showcases that display help text with remote-key name highlights.
6. Architectural patterns
These patterns are not showcase-specific. Any RSG 2.0 SDK app that uses panels, fullscreen views, dialogs, or menu navigation can adopt them directly.
Pattern: fullscreen scene with back navigation
This pattern builds a fullscreen view that the user can leave with the Back key.
- When to use: When you need a fullscreen view (for example, a settings screen, detail page, player, or visualization) that the user can leave with the Back key. The pattern is: wrap content in
BackSceneWrapper, register the view factory in a registry, and navigate to it by ID. - Structure:
- Create a component wrapped in
BackSceneWrapper(withtitleand optionalshowBackHint,showOptions). - Register it in a scene registry (
main-scene.tsx→SCENESarray) with a unique string ID. - Optionally create a preview/info panel using
InfoPanelto show before entering the scene. - Trigger navigation from a menu item or any component via
setScreen(id).
- Create a component wrapped in
- Reference implementation:
examples/showcase/src/components/showcases/poster-showcase/poster-scene-showcase.tsx(scene) +examples/showcase/src/components/showcases/poster-showcase/poster-showcase.tsx(info panel) - Reference implementation:
examples/showcase/src/components/showcases/busy-spinner-showcase/busy-spinner-scene-showcase.tsx(scene withonUnhandledKey)
Pattern: FocusBoundary (app-level virtual focus)
- When to use: When routing remote keys through TypeScript instead of distributed
KeyHandler/FocusableGroupwrappers. This showcase is the reference implementation of that pattern. - Structure:
- Anchor node extends
FocusBoundaryBasewithkeyEvent,focusActive,handledKeys,focusPathfields. - Single
RootFocusBoundaryat app root withinitialFocus={ACTIVE_REGION_REF}. - Each active region (menu or fullscreen scene) mounts a nested
FocusBoundarywithfocusId={ACTIVE_REGION_REF}andRegionShellFocusablefor SceneGraph-native children. - Scene keys on
BackSceneWrapperviaonUnhandledKey; irregular grids use innerFocusBoundary+navigationMap+useFocusable. - Do not span
FocusBoundaryacross PanelSet to ListPanel slides; keep panel menus on SceneGraph-native focus (jumpTo,slidingBack,onFocusedChild).
- Anchor node extends
- Reference implementation:
examples/showcase/src/components/showcase-app.tsx - Reference implementation:
examples/focus-boundary/(API examples) - Docs:
documentation/guides/focus-management/focus-boundary.md
Pattern: panel-based content view
This pattern shows content in a side panel instead of a fullscreen view.
- When to use: When content fits within a side panel and does not need to take over the full screen (for example, a detail view, a settings form, a text description, a component preview). Panels slide in from the right inside a PanelSet and can chain to deeper panels.
- Structure:
- Create a component using
<panel panelSize="medium" focusable={false} hasNextPanel={false}>with LayoutGroup for content arrangement. - Wire it into a menu as a
getNextPanelfactory on aListMenuPanelorSceneDialogMenuitem.
- Create a component using
- Reference implementation:
examples/showcase/src/components/showcases/label-showcases/label-showcase-panel.tsx(panel using Boundary for visual grouping) - Reference implementation:
examples/showcase/src/components/showcases/group-showcase.tsx(panel with animation)
Pattern: hierarchical menu navigation
This pattern builds a multi-level categorized menu.
- When to use: When you need a multi-level categorized menu (for example, Settings → Audio → Equalizer; Browse → Genre → SubGenre). Two variants:
- SceneDialogMenu: items can open fullscreen scenes (
sceneDialogId), open modal dialogs (isDialog: true), or drill into sub-panels (getNextPanel). You can use it when items trigger heterogeneous navigation targets. - ListMenuPanel: items drill into child panels only (
getNextPanel). You can use it for pure panel-to-panel navigation.
Both supportslidingBackfor back-navigation animation and focus restoration across depth levels.
- SceneDialogMenu: items can open fullscreen scenes (
- Reference implementation (SceneDialogMenu):
examples/showcase/src/components/showcases/dialog-showcases/index.tsx - Reference implementation (ListMenuPanel):
examples/showcase/src/components/showcases/label-showcases/index.tsx - Reference implementation (ListMenuPanel):
examples/showcase/src/components/showcases/group-submenu.tsx
Pattern: options key opens the property chooser (runtime config)
This pattern lets users change properties at runtime with the Options key.
- When to use: When any screen should let users change settings or component properties at runtime via the Options (
*) remote key. Applicable to settings screens, customization flows, or any view with configurable parameters. It is not limited to showcases. - Structure:
- Define an
IPropertyConfig[]array describing each configurable property and its options. - Hold a
createSignal<Record<string, unknown>>for current property values. - Pass
onUnhandledKey={{ options: makeOptionsUnhandledKey(onOptionsKey) }}onBackSceneWrapper(or a nestedFocusBoundaryfor irregular grids). - Call
openPropertyChooser(setDialog, title, config, propsState, setPropsState, defaultProps)in the key handler. - Spread
{...propsState()}onto the target component to apply changes reactively. - Optionally use
makeCodeText(...)to display current values in aCodePanel. - Pass
showOptions={true}andoptionsTexttoBackSceneWrapperto show the hint in the Overhang.
- Define an
- Reference implementation:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx
Pattern: image resolution imports
This pattern imports images that have FHD and HD variants.
- When to use: When importing images that have FHD and HD variants. The SDK's build system resolves
*glob patterns in import paths to the correct resolution file at build time. You can use it in any app, not just showcases. - Syntax:
import { uri as myImage } from "./images/my-image-*.webp"; - Reference implementation:
examples/showcase/src/components/scene-wrapper.tsx(import { uri as logo } from "./images/sc-logo-*.webp") - Reference implementation:
examples/showcase/src/components/showcases/busy-spinner-showcase/busy-spinner-scene-showcase.tsx(import { uri as busySpinnerImage } from "./images/busyspinner-*.webp")
7. Dialog patterns
These patterns cover building and registering dialogs.
Pattern: composable StandardDialog
This pattern composes a modal dialog from title, content, and button areas.
- When to use: When building any modal dialog with custom content layout, such as confirmation prompts, forms, wizards, error messages, and onboarding flows. You can compose StandardDialog from
StdDlgTitleArea,StdDlgContentArea, andStdDlgButtonArea. You can populate the content area withStdDlgTextItem, StdDlgActionCardItem,StdDlgCustomItem,StdDlgProgressItem, and so on. You must handle the close lifecycle. See Pattern: dialog close lifecycle for more information. - Reference implementation:
examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx(example of the close lifecycle)
Pattern: StandardMessageDialog (quick message)
StandardMessageDialog (quick message)This pattern shows a message dialog without a custom content layout.
- When to use: When you need a dialog with a title, one or more message strings, and buttons, without a custom content layout. Covers confirmations, alerts, and notifications. You can use StandardMessageDialog instead of composing areas manually.
- Reference implementation:
examples/showcase/src/components/showcases/list-and-grid-showcase/item-selected-dialog.tsx - Reference implementation:
examples/showcase/src/components/showcases/dialog-showcases/terms-conditions-dialog.tsx
Pattern: dialog with child navigation (stacking)
This pattern opens a sub-dialog from a dialog and returns results to the parent.
- When to use: When a dialog needs to open a sub-dialog and return to the parent with results (for example, Settings, then a sub-category picker, then back to Settings with the selection). The
DialogContextstack manages backup/restore of parent data. You can usependingChildandopenChildDialogto push, andgetChildCloseParamsto process the child's return data. - Reference implementation:
examples/showcase/src/components/showcases/dialog-showcases/app-settings/app-settings-dialog.tsx - Reference implementation:
examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx
Pattern: dialog close lifecycle
This pattern defines how a dialog closes.
- When to use: Every StandardDialog (or variant) must follow this lifecycle. You must guard against duplicate
onWasClosedcalls with ahasBeenClosedflag. - Flow:
- User presses a button →
onButtonSelected(index)fires → batchsetCloseDialog(true)+setSelectedButton(index). - StandardDialog begins its close animation.
- Animation finishes →
onWasClosedfires. - Call
contextCloseDialog({ reason, buttonId, ... })→ DialogContext clears the dialog.
- User presses a button →
- Reference implementation:
examples/showcase/src/components/showcases/dialog-showcases/simple-dialog.tsx(fully documented lifecycle)
Pattern: registering a new dialog
This pattern adds a new dialog type to an app.
- When to use: When adding a new dialog type to any app that uses
DialogContext. - Steps:
- Create the dialog component following the close lifecycle pattern.
- Register it in the dialog registry (in this app:
main-scene.tsx→DIALOGSarray) with a unique string ID. - Open it from anywhere via
setDialog(id, onCloseCallback, optionalData).
- Reference implementation:
examples/showcase/src/components/main-scene.tsx(DIALOGS array)
8. List and grid scene patterns
These patterns cover list and grid scenes.
Pattern: fullscreen list/grid view
This pattern builds a fullscreen view around a list or grid component.
- When to use: When building any fullscreen view centered on a list or grid component, such as media browsers, channel guides, settings lists, and category grids. The pattern combines a
BackSceneWrapper, a ContentNode data tree, focus tracking, item selection handling, and optional runtime property editing. - Structure:
- Wrap in
BackSceneWrapperwithshowOptions={true}if property editing is needed. - Build a ContentNode tree for the list/grid content (often reactive via
createMemo). - Track the focused item with
createSignal<number>and display viafocusLabelText. - Handle item selection (for example, open a dialog, navigate to a detail view, trigger an action).
- Optionally add a
CodePanelwithmakeCodeTextto display current property values. - Optionally wire the Options key to
openPropertyChooserfor runtime configuration.
- Wrap in
- Reference implementation:
examples/showcase/src/components/showcases/list-and-grid-showcase/poster-grid/poster-grid-scene-showcase.tsx(complete pattern)
Pattern: registering a new scene
This pattern adds a new fullscreen view to an app.
- When to use: When adding a new fullscreen view to any app that uses
ScreenRegistryContext(or the underlyingScreenControllerContext). - Steps:
- Create the view component wrapped in
BackSceneWrapper. - Register it in the scene registry (in this app:
main-scene.tsx→SCENESarray) with a unique string ID. - Optionally create a preview/info panel using
InfoPanel. - Add a menu item or trigger that calls
setScreen(id)to navigate to it.
- Create the view component wrapped in
- Reference implementation:
examples/showcase/src/components/main-scene.tsx(SCENES array) +examples/showcase/src/components/main-menu.tsx(menu items)
9. Media playback patterns
These patterns cover audio and video playback.
Pattern: imperative media playback via refs
This pattern controls media playback through imperative refs.
- When to use: When controlling Audio, Video, or
SoundEffectplayback. Instead of binding a reactivecontrolsignal to the component'scontrolprop, obtain an imperative ref (AudioRef,VideoRef, orSoundEffectRef) and call its methods directly. This approach avoids timing issues with batched signal updates and makes the control flow explicit. - Structure:
- Declare a ref variable:
let audioRef!: AudioRef(orVideoRef, orSoundEffectRef). - Pass it to the component:
<Audio ref={audioRef} ... />. - Start playback in
onMount:audioRef.play(). - Stop and release resources in
onCleanup:audioRef?.stop(). - Call ref methods in event handlers for play/pause/stop/skip.
- Declare a ref variable:
- The
SoundEffectRefobject exposes only.play()and.stop(); the Roku SoundEffect node does not support pause, resume, or skip. - Reference implementation:
examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx(AudioRefwithplay,pause,resume,stop) - Reference implementation:
examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-scene.tsx(VideoRefwithplay,stop) - Reference implementation:
examples/showcase/src/components/showcases/sound-effect-showcase/sound-effect-showcase.tsx(SoundEffectRefwithplay)
Pattern: audio playlist with transport controls & track skipping
This pattern builds an audio player with playlist support.
- When to use: When building an audio player with playlist support, transport buttons, and track-skip functionality. Demonstrates how to combine
AudioRefimperative control withnextContentIndexfor explicit track jumps,onStatefor state tracking, andonContentIndexfor active-track highlighting. - Structure:
- Load a playlist via
getAudioPlaylist()and build a ContentNode tree withcontentIsPlaylistandloop. - Track the active track index with a
createSignalupdated by theonContentIndexcallback. - To skip: set
nextContentIndexto the target index (with modular arithmetic for wraparound), then callaudioRef.play(); theplaycommand restarts playback from the index specified bynextContentIndex. - Toggle play/pause via
audioRef.pause()andaudioRef.resume()(notplay, which restarts the track). - Display playback state from the
onStatecallback.
- Load a playlist via
- Key fields:
contentIsPlaylist,loop,nextContentIndex,onState,onContentIndex - Reference implementation:
examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx
Pattern: two-phase media exit (stop then navigate)
This pattern stops media playback before navigating away.
- When to use: When a media playback scene needs to stop audio or video and then navigate away. Navigating immediately after calling
stop()can tear down the scene while media resources are still active. Both the Audio and Video showcases use the same two-phase approach to release resources cleanly. - Flow:
- User presses Back → set a local
exit/shouldExitflag and callref.stop(). - The media node transitions through states and eventually reports
"stopped"throughonState. - Inside
onState, checkstate === "stopped"and the exit flag → navigate away (for example,setScreen(null)orcloseFullscreenVideo()).
- User presses Back → set a local
- Why: The media node may pass through intermediate states (buffering, paused) before confirming
"stopped". Deferring navigation to theonStatecallback releases the resources fully before the app navigates. - Reference implementation:
examples/showcase/src/components/showcases/audio-showcase/audio-scene-showcase.tsx(setsexitflag, waits for"stopped"inonState, callssetScreen(null)) - Reference implementation:
examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-scene.tsx(setsshouldExitflag, waits for"stopped"inonState, callscloseFullscreenVideo())
10. Compiled (BRS/XML) components
These compiled components are SceneGraph XML components with BrightScript implementations.
Custom list/grid item components
These components render the items in list and grid components.
- Name:
MarkupGridItem,MarkupListItem,RowListItem,TimeGridChannelItem,ZoomRowListItem - When to use: When a list or grid component requires a custom item renderer (MarkupGrid, MarkupList, RowList, TimeGrid, ZoomRowList). These are SceneGraph XML components with BrightScript implementations, compiled from TypeScript source. They define the visual layout of each item in the list/grid.
- Implementation files:
examples/showcase/src/compiled-components/MarkupGridItem.xml,.brs;examples/showcase/src/compiled-components/MarkupListItem.xml,.brs;examples/showcase/src/compiled-components/RowListItem.xml,.brs;examples/showcase/src/compiled-components/TimeGridChannelItem.xml,.brs;examples/showcase/src/compiled-components/ZoomRowListItem.xml,.brs - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/markup-grid/markup-grid-scene-showcase.tsx(references MarkupGridItem) - Usage example:
examples/showcase/src/components/showcases/list-and-grid-showcase/row-list/row-list-scene-showcase.tsx(references RowListItem)
BaseAppScene
BaseAppScene hosts the TypeScript app.
- Name:
BaseAppScene - When to use: This scene is the base SceneGraph XML scene that hosts the TypeScript app. Imported in
examples/showcase/src/index.ts. You should modify this scene only when you change the scene bootstrap. - Implementation file:
examples/showcase/src/compiled-components/BaseAppScene.xml,.brs - Usage example:
examples/showcase/src/index.ts(imported at top level)
Adding new views: quick reference
The following sections list the steps for adding each kind of view.
Adding a new fullscreen scene
To add a new fullscreen scene, follow these steps:
- Create
examples/showcase/src/components/showcases/<name>/<name>-scene-showcase.tsx→ wrap inBackSceneWrapper. - Optionally create
examples/showcase/src/components/showcases/<name>/<name>-info-panel.tsx→ useInfoPanelwith title, text, andshowOkMessage. - Register the scene in
examples/showcase/src/components/main-scene.tsx→ add["<scene-id>", () => <YourScene />]toSCENES. - Add to menu in
examples/showcase/src/components/main-menu.tsxor a submenu →{ id: "...", title: "...", sceneDialogId: "<scene-id>", getNextPanel: () => <YourInfoPanel /> }. - If the scene needs runtime property editing: follow the Options key property chooser pattern.
Adding a new dialog
To add a new dialog, follow these steps:
- Create the dialog component in
examples/showcase/src/components/showcases/dialog-showcases/<name>-dialog.tsx→ follow the Dialog Close Lifecycle pattern. - Optionally create an info panel in
examples/showcase/src/components/showcases/dialog-showcases/<name>-panel.tsx→ useInfoPanel. - Register in
examples/showcase/src/components/main-scene.tsx→ add toDIALOGSarray. - Add to
examples/showcase/src/components/showcases/dialog-showcases/index.tsx→ add item withsceneDialogId: "<dialog-id>"andisDialog: true.
Adding a new panel view
To add a new panel view, follow these steps:
- Create
examples/showcase/src/components/showcases/<name>/<name>-panel.tsx→ use<panel panelSize="medium" focusable={false} hasNextPanel={false}>. - Add to a menu's
itemsarray withgetNextPanel: () => <YourPanel />.
Adding a new submenu (category grouping)
To add a new submenu, follow these steps:
- Use
SceneDialogMenuif items open scenes/dialogs, orListMenuPanelif items only open panels. - Wire into the parent menu's
getNextPanelfactory. - Pass
slidingBackprop through for back-navigation animation.
File index: key files at a glance
The following table lists the key files in the app.
| File | Role |
|---|---|
examples/showcase/src/index.ts | App entry point |
examples/showcase/src/components/showcase-app.tsx | Root component + provider tree |
examples/showcase/src/components/main-scene.tsx | Scene & dialog registry |
examples/showcase/src/components/menu-scene.tsx | Home screen (fallback) |
examples/showcase/src/components/main-menu.tsx | Top-level menu items |
examples/showcase/src/components/scene-wrapper.tsx | Fullscreen view with Overhang chrome + Back key |
examples/showcase/src/components/scene-dialog-menu.tsx | List menu with scene/dialog triggers |
examples/showcase/src/components/list-menu-panel.tsx | List menu with panel drill-down |
packages/navigation/src/screen-controller/screen-controller.tsx | @roku-sdk/navigation: factory-based screen stack and fullscreen view switching |
examples/showcase/src/components/screen-registry/screen-registry.tsx | App-level id-based registry wrapper around @roku-sdk/navigation's ScreenControllerContext |
examples/showcase/src/components/showcases/dialog-showcases/dialog-context.tsx | Dialog state management |
examples/showcase/src/components/showcases/list-and-grid-showcase/time-grid/fullscreen-video-context.tsx | Video playback state |
examples/showcase/src/components/info-panel/info-panel.tsx | Titled rich-text panel with overflow scroll |
examples/showcase/src/components/code-panel.tsx | Poster-backed panel with custom font |
examples/showcase/src/components/tbd-panel.tsx | Styled message placeholder panel |
examples/showcase/src/components/showcases/common/boundary.tsx | Auto-sizing measured container |
examples/showcase/src/components/property-chooser/property-chooser-dialog.tsx | Data-driven option picker dialog |
examples/showcase/src/components/property-chooser/property-chooser-types.ts | Property config/option types |
examples/showcase/src/components/property-chooser/property-chooser-utils.ts | Property apply/build/format helpers |
examples/showcase/src/components/showcases/dialog-showcases/dialog-palette.tsx | RsgPalette color scheme for dialogs |
examples/showcase/src/components/drawing-styles.ts | Reusable DrawingStyle maps for MultiStyleLabel |
examples/showcase/src/components/showcases/list-and-grid-showcase/showcase-utils.ts | Scene helper functions (property chooser, key handler, code text) |
examples/showcase/src/components/showcases/list-and-grid-showcase/item-selected-dialog.tsx | Single-message OK dialog |
examples/showcase/src/components/showcases/showcase-utils/picsum-utils.ts | Remote image URL builder |
examples/showcase/src/components/showcases/showcase-utils/video-playlist.ts | Video playlist data loader |
examples/showcase/src/components/showcases/showcase-utils/audio-playlist.ts | Audio playlist data loader |
Updated about 3 hours ago