How to render WebView UI controls on top of KeplerVideoSurfaceView on Vega OS?

Hi,

I’m building a Vega OS app (React Native with Kepler platform) that uses a WebView loading a remote web app URL alongside a native DASH player using @amazon-devices/react-native-w3cmedia.

Architecture:
WebView loads a remote web app that provides the UI (transport controls, menus, etc.)
Native side handles DASH video playback using VideoPlayer + KeplerVideoSurfaceView + Dash.js
Communication between WebView and React Native is via postMessage / injectJavaScript

Problem:

When video is playing, the WebView UI controls are not visible on top of the video. The KeplerVideoSurfaceView hardware surface always renders above the WebView regardless of React Native zIndex or elevation values.

What I’ve tried (all failed):
Setting zIndex on WebView (makes WebView visible but video disappears)
Setting zIndex/elevation on NativePlayer container
Setting WebView backgroundColor to ‘transparent’

Questions:

Is there a API available on Vega OS that allows a WebView to overlay a video surface?

Is there a supported way to make a WebView transparent so the native video surface shows through, while the WebView HTML content (controls) renders on top?

Environment:

Platform: Vega SDK version (0.23)

@amazon-devices/react-native-kepler: ^2.0.0

@amazon-devices/react-native-w3cmedia: ^2.2.21
@amazon-devices/webview: ^3.3.x

Hi @Hari_Krishnan,

Thank you for the detailed description of your setup.

Based on the current Vega documentation, here’s what we can confirm:

  1. KeplerVideoSurfaceView is a dedicated video rendering surface - it renders video frames on the screen and is separate from the React Native component tree. Apps receive a surface handle via the onSurfaceViewCreated callback and pass it to the VideoPlayer instance.
  2. Apps are expected to build their own media controls UI - the official VideoPlayer API states: “It doesn’t render video to the screen by default, nor does it render the media controls GUI. Apps are expected to build their own media controls UI and control the playback experience.”
  3. React Native’s zIndex and elevation properties control ordering within the RN view hierarchy but do not affect the hardware video surface layer, which is why the approaches you tried did not work.

We are looking into this further and will get back to you with more specific guidance on supported overlay patterns for rendering UI controls on top of the video surface.

Thanks for helping us improve the Vega platform.

Warm regards,
Aishwarya

Hi @amen

Thank you for the explanation and for looking into this.

I wanted to check if there have been any updates regarding the supported overlay patterns for rendering UI controls on top of KeplerVideoSurfaceView.

We’re currently evaluating options for displaying React Native UI elements (playback controls, overlays, etc.) over video playback, and it would be helpful to understand whether Vega provides any supported approach for layering UI above the dedicated video rendering surface.

Could you please share any findings or guidance from your investigation when you get a chance?

Thank you for your help.

Warm regards,
Hari Krishnan

Hi @amen ,
Will there be a way to display a WebView over video playback, or is that something that will never be possible on VegaOS? Is this something VegaOS is planning to support in the future?
Thanks,
Hari

Hi @Hari_Krishnan,

Thank you for your patience while we investigated this. Vega OS does support rendering a transparent WebView on top of video playback, which is exactly the pattern you need for overlaying UI controls over KeplerVideoSurfaceView.

How It Works

The approach is to layer a WebView (from @amazon-devices/webview) as a sibling on top of KeplerVideoSurfaceView, with the WebView set to a fully transparent background. The video shows through the transparent WebView, while your HTML-based controls render on top.

Steps to Implement

  1. Update your Metro config - Add 'html' to the assetExts resolver so Metro can bundle local HTML files as assets:
const defaultConfig = getDefaultConfig(__dirname);
const config = {
  resolver: {
    assetExts: defaultConfig.resolver.assetExts.includes('html')
      ? defaultConfig.resolver.assetExts
      : [...defaultConfig.resolver.assetExts, 'html'],
  },
};
module.exports = mergeConfig(defaultConfig, config);
  1. Load your HTML overlay as an asset source - Use Image.resolveAssetSource to resolve the local HTML file:
import {Image} from 'react-native';

const overlaySource = {
  uri: Image.resolveAssetSource(require('../assets/player-overlay.html')).uri,
};
  1. Layer the components - Place KeplerVideoView and a transparent WebView container as siblings inside the same parent View:
<View style={styles.container}>
  {useKeplerVideoView ? (
    <KeplerVideoView style={styles.backgroundVideo} videoPlayer={video.current} />
  ) : null}
  <View style={styles.modalContainer}>
    <WebView
      ref={webRef}
      source={overlaySource}
      style={styles.overlayWebView}
      onMessage={handleTransportMessage}
      onLoadStart={() => setIsWebViewReady(false)}
      onLoad={() => setIsWebViewReady(true)}
    />
  </View>
</View>
  1. Key styles - The WebView and its container must both have transparent backgrounds:
const styles = StyleSheet.create({
  container: { flex: 1 },
  overlayWebView: {
    flex: 1,
    backgroundColor: 'rgb(0,0,0, 0)',
  },
  modalContainer: {
    flex: 1,
    backgroundColor: 'rgba(0, 0, 0, 0)',
    position: 'absolute',
    top: 0,
    left: 0,
    width: 1920,
    height: 1080,
  },
});
  1. Handle TV remote input - Use useTVEventHandler from @amazon-devices/react-native-kepler to capture remote control events (e.g., the select button) and forward them into the WebView via injectJavaScript.

  2. Bidirectional communication - Your HTML overlay should send messages back to React Native using window.ReactNativeWebView.postMessage(...), and your React Native side should handle them via the WebView’s onMessage prop. To push state updates into the WebView, use webRef.current.injectJavaScript(...).

  3. Track WebView readiness - Gate all injectJavaScript calls behind an isWebViewReady state flag (set to true in onLoad, false in onLoadStart) to avoid calling into the WebView before it’s ready.

  4. Create your own HTML overlay page - Your HTML file should set background: transparent on both html and body elements. Only your actual control elements (buttons, text) should have visible styling. The HTML should expose functions that React Native can call via injectJavaScript and use postMessage to send user actions back.

This requires @amazon-devices/webview for the WebView component

This requires @amazon-devices/react-native-kepler for useTVEventHandler

Note: The code example uses KeplerVideoView (from @amazon-devices/react-native-w3cmedia), which is the component used for video rendering.

Let us know if you have any further questions!

Warm regards,
Aishwarya