The Expo SDK provides a comprehensive set of libraries and tools for building cross-platform mobile applications using React Native.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The Expo DOM component system enables React Native applications to render DOM components within WebView contexts. This system provides a bridge between React Native and web technologies, allowing developers to create hybrid components that can access DOM APIs while integrating seamlessly with React Native applications.
Register a React component as a DOM component that runs within a WebView context.
/**
* Registers a React component to run as a DOM component within a WebView
* @param AppModule - React component to register as the DOM component root
*/
function registerDOMComponent(AppModule: any): void;Create imperative handles for DOM components that can be called from the React Native side.
/**
* React hook for creating imperative handles in DOM components
* @param ref - React ref to bind the handle to
* @param init - Function that creates the imperative handle object
* @param deps - Dependency array for recreating the handle
*/
function useDOMImperativeHandle<T extends DOMImperativeFactory>(
ref: Ref<T>,
init: () => T,
deps?: DependencyList
): void;Utility to detect if code is running in a DOM component context.
/**
* Constant indicating if the current environment is a DOM component
*/
const IS_DOM: boolean;/**
* Interface for imperative handle factories in DOM components
*/
interface DOMImperativeFactory {
[key: string]: (...args: JSONValue[]) => void;
}
/**
* Props interface for DOM components with WebView configuration
*/
interface DOMProps extends Omit<RNWebViewProps, 'source'> {
/** Whether to resize the native WebView size based on the DOM content size */
matchContents?: boolean;
/** Whether to use @expo/dom-webview as the underlying WebView implementation */
useExpoDOMWebView?: boolean;
}
/**
* Supported JSON value types for DOM component communication
*/
type JSONValue = boolean | number | string | null | JSONArray | JSONObject;
interface JSONArray extends Array<JSONValue> {}
interface JSONObject {
[key: string]: JSONValue | undefined;
}
/**
* Message structure for communication between React Native and DOM components
*/
type BridgeMessage<TData extends JSONValue> = {
type: string;
data: TData;
};import React from 'react';
import { registerDOMComponent, useDOMImperativeHandle } from 'expo/dom';
interface CanvasComponentProps {
width: number;
height: number;
backgroundColor?: string;
}
interface CanvasHandle {
drawCircle: (x: number, y: number, radius: number, color: string) => void;
clear: () => void;
getImageData: () => string;
}
function CanvasComponent({ width, height, backgroundColor = 'white' }: CanvasComponentProps) {
const canvasRef = React.useRef<HTMLCanvasElement>(null);
const handleRef = React.useRef<CanvasHandle>(null);
// Create imperative handle for React Native to call
useDOMImperativeHandle<CanvasHandle>(
handleRef,
() => ({
drawCircle: (x: number, y: number, radius: number, color: string) => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fill();
},
clear: () => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, width, height);
},
getImageData: () => {
const canvas = canvasRef.current;
if (!canvas) return '';
return canvas.toDataURL();
}
}),
[width, height, backgroundColor]
);
return (
<canvas
ref={canvasRef}
width={width}
height={height}
style={{ backgroundColor, display: 'block' }}
/>
);
}
// Register the component as a DOM component
registerDOMComponent(CanvasComponent);import { IS_DOM } from 'expo/dom';
function MyComponent() {
if (IS_DOM) {
// Code running in DOM component context
// Has access to DOM APIs, document, window, etc.
return (
<div>
<h1>DOM Component</h1>
<p>This is running in a WebView with full DOM access</p>
</div>
);
} else {
// Code running in React Native context
return (
<View>
<Text>React Native Component</Text>
</View>
);
}
}DOM components communicate with React Native through a message-passing system:
// In DOM component
function sendMessageToReactNative(type: string, data: any) {
// Messages are sent through the WebView bridge
if (typeof window.ReactNativeWebView !== 'undefined') {
window.ReactNativeWebView.postMessage(JSON.stringify({ type, data }));
}
}
// Example: Notify React Native of user interaction
function handleUserClick(userData: any) {
sendMessageToReactNative('user_interaction', {
action: 'click',
data: userData,
timestamp: Date.now(),
});
}// DOM components receive props from React Native
function MyDOMComponent({ initialData, onDataChange }) {
const [data, setData] = useState(initialData);
const handleChange = (newData) => {
setData(newData);
onDataChange?.(newData); // Callback to React Native
};
return (
<div>
{/* Component UI */}
</div>
);
}DOM components run within WebView contexts, which means:
// DOM components should validate all data from React Native
function validateProps(props: any): boolean {
// Implement proper validation
return typeof props === 'object' && props !== null;
}
function SecureDOMComponent(props: any) {
if (!validateProps(props)) {
return <div>Invalid props provided</div>;
}
return (
<div>
{/* Safe to use props */}
</div>
);
}