;
+ saveData: (data: {
+ name: string;
+ value: number;
+ }) => Promise<{ success: boolean }>;
+ dom?: import("expo/dom").DOMProps;
+}
+
+export default function DOMComponent({ showAlert, saveData }: Props) {
+ const handleClick = async () => {
+ await showAlert("Hello from the webview!");
+ const result = await saveData({ name: "test", value: 42 });
+ console.log("Save result:", result);
+ };
+
+ return ;
+}
+```
+
+## Using Web Libraries
+
+DOM components can use any web library:
+
+```tsx
+// components/syntax-highlight.tsx
+"use dom";
+
+import SyntaxHighlighter from "react-syntax-highlighter";
+import { docco } from "react-syntax-highlighter/dist/esm/styles/hljs";
+
+interface Props {
+ code: string;
+ language: string;
+ dom?: import("expo/dom").DOMProps;
+}
+
+export default function SyntaxHighlight({ code, language }: Props) {
+ return (
+
+ {code}
+
+ );
+}
+```
+
+```tsx
+// components/chart.tsx
+"use dom";
+
+import {
+ LineChart,
+ Line,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+} from "recharts";
+
+interface Props {
+ data: Array<{ name: string; value: number }>;
+ dom: import("expo/dom").DOMProps;
+}
+
+export default function Chart({ data }: Props) {
+ return (
+
+
+
+
+
+
+
+ );
+}
+```
+
+## CSS in DOM Components
+
+CSS imports must be in the DOM component file since they run in isolated context:
+
+```tsx
+// components/styled-component.tsx
+"use dom";
+
+import "@/styles.css"; // CSS file in same directory
+
+export default function StyledComponent({
+ dom,
+}: {
+ dom: import("expo/dom").DOMProps;
+}) {
+ return (
+
+
Styled Content
+
+ );
+}
+```
+
+Or use inline styles / CSS-in-JS:
+
+```tsx
+"use dom";
+
+const styles = {
+ container: {
+ padding: 20,
+ backgroundColor: "#f0f0f0",
+ },
+ title: {
+ fontSize: 24,
+ color: "#333",
+ },
+};
+
+export default function StyledComponent({
+ dom,
+}: {
+ dom: import("expo/dom").DOMProps;
+}) {
+ return (
+
+
Styled Content
+
+ );
+}
+```
+
+## Expo Router in DOM Components
+
+The expo-router `` component and router API work inside DOM components:
+
+```tsx
+"use dom";
+
+import { Link, useRouter } from "expo-router";
+
+export default function Navigation({
+ dom,
+}: {
+ dom: import("expo/dom").DOMProps;
+}) {
+ const router = useRouter();
+
+ return (
+
+ );
+}
+```
+
+### Router APIs That Require Props
+
+These hooks don't work directly in DOM components because they need synchronous access to native routing state:
+
+- `useLocalSearchParams()`
+- `useGlobalSearchParams()`
+- `usePathname()`
+- `useSegments()`
+- `useRootNavigation()`
+- `useRootNavigationState()`
+
+**Solution:** Read these values in the native parent and pass as props:
+
+```tsx
+// app/[id].tsx (native)
+import { useLocalSearchParams, usePathname } from "expo-router";
+import DOMComponent from "@/components/dom-component";
+
+export default function Screen() {
+ const { id } = useLocalSearchParams();
+ const pathname = usePathname();
+
+ return ;
+}
+```
+
+```tsx
+// components/dom-component.tsx
+"use dom";
+
+interface Props {
+ id: string;
+ pathname: string;
+ dom?: import("expo/dom").DOMProps;
+}
+
+export default function DOMComponent({ id, pathname }: Props) {
+ return (
+
+
Current ID: {id}
+
Current Path: {pathname}
+
+ );
+}
+```
+
+## Detecting DOM Environment
+
+Check if code is running in a DOM component:
+
+```tsx
+"use dom";
+
+import { IS_DOM } from "expo/dom";
+
+export default function Component({
+ dom,
+}: {
+ dom?: import("expo/dom").DOMProps;
+}) {
+ return {IS_DOM ? "Running in DOM component" : "Running natively"}
;
+}
+```
+
+## Assets
+
+Prefer requiring assets instead of using the public directory:
+
+```tsx
+"use dom";
+
+// Good - bundled with the component
+const logo = require("../assets/logo.png");
+
+export default function Component({
+ dom,
+}: {
+ dom: import("expo/dom").DOMProps;
+}) {
+ return
;
+}
+```
+
+## Usage from Native Components
+
+Import and use DOM components like regular components:
+
+```tsx
+// app/index.tsx
+import { View, Text } from "react-native";
+import WebChart from "@/components/web-chart";
+import CodeBlock from "@/components/code-block";
+
+export default function HomeScreen() {
+ return (
+
+ Native content above
+
+
+
+
+
+ Native content below
+
+ );
+}
+```
+
+## Platform Behavior
+
+| Platform | Behavior |
+| -------- | ----------------------------------- |
+| iOS | Rendered in WKWebView |
+| Android | Rendered in WebView |
+| Web | Rendered as-is (no webview wrapper) |
+
+On web, the `dom` prop is ignored since no webview is needed.
+
+## Tips
+
+- DOM components hot reload during development
+- Keep DOM components focused — don't put entire screens in webviews
+- Use native components for navigation chrome, DOM components for specialized content
+- Test on all platforms — web rendering may differ slightly from native webviews
+- Large DOM components may impact performance — profile if needed
+- The webview has its own JavaScript context — cannot directly share state with native
diff --git a/plugins/expo/skills/use-dom/agents/openai.yaml b/plugins/expo/skills/use-dom/agents/openai.yaml
new file mode 100644
index 00000000..1ca06f6e
--- /dev/null
+++ b/plugins/expo/skills/use-dom/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Use DOM"
+ short_description: "Use Expo DOM components to run web React code in native webviews and unchanged on web"
+ default_prompt: "Use $use-dom to migrate web components into Expo via 'use dom', configure DOM props, expose native actions safely, use web-only libraries, and keep DOM components separate from native routes."