# Why
TesterArmy is adding Expo to the [e2e
showcase](https://e2e.tester.army/examples) and asked for an Expo
example that runs on Expo Simulators. This folder is that example. The
showcase lists it by folder URL, so it lives here and installs with `npx
create-expo --example with-e2e`.
# How
- One screen: a greeting form built with `@expo/ui` universal components
inside a `GlassView` from `expo-glass-effect`, with native tabs. A
second tab explains the tests.
- The five tests from TesterArmy's with-expo starter: three locator
tests and two agent tests that skip without `AI_GATEWAY_API_KEY`.
- `e2e.config.ts` has `ios`, `android`, and `web` targets. With
`E2E_IOS_BUILD_ID` or `E2E_ANDROID_BUILD_ID` set, the mobile targets run
on Expo Simulators through `@e2e-dev/eas`. Without them, they drive the
local simulator or emulator. The web target lets the runner pick a free
port.
- `eas.json` adds an `e2e` build profile. `.eas/workflows/e2e.yml`
builds both platforms and runs the suite on Expo Simulators from Linux
runners.
- `AGENTS.md` tells coding agents to install the Expo skills and which
skill to use for the screen, Expo Simulators, and the workflow.
# Test Plan
- [x] `tsc --noEmit` and `eslint .` pass.
- [x] Fresh install of the folder (from this branch, since `create-expo
--example` reads master), then the README steps: `npm run ios:release`
and `npm run test:e2e:ios` on an iPhone 17 simulator (iOS 26.5). Three
locator tests pass, the agent tests skip without a key.
- [x] `npm run test:e2e:web` in the fresh install: three pass.
- [x] `npm run android:release` and `npm run test:e2e:android` on a
Pixel 9 emulator (Android 16): three pass.
- [ ] The agent tests with a model key.
- [ ] A run on Expo Simulators with an `e2e` profile build
(`E2E_IOS_BUILD_ID`).
- [ ] `eas workflow:validate` and one workflow run. Both need the
project linked with `eas init`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5.1 <[email protected]>
Co-authored-by: Tori Expo <[email protected]>
## Why
Follow-up https://github.com/expo/expo/pull/50738
Update to SDK 58.
Fix ENG-27063
## How
- Move the code to `src/app` and `src/components`, with Expo UI buttons
in platform-specific files (`.android.tsx`, `.ios.tsx`) and a universal
`BottomSheet`.
- Save screenshots with `MediaLibrary.Asset.create()` on Android and
iOS, and download them with `react-native-view-shot` on web. Remove
`dom-to-image` and `types.d.ts`.
- Use React Native Gesture Handler 3 hooks and Reanimated
`get()`/`set()` for the sticker.
- Replace the placeholder photo and emoji (credits in
`assets/images/CREDITS.md`), and add Android adaptive icon layers.
- Update dependencies to SDK 58 (preview). A follow-up upgrades them to
the stable release.
## Why
The iOS widget showed correctly in full-color but was **completely covered** in iOS 18+ tinted/clear modes. The full-bleed gradient `Rectangle` was drawn as
regular content (not the container background), so WidgetKit re-rendered it as an opaque monochrome block that buried the text.
## How
Gate the gradient behind the rendering mode (in `widgets/MyWidget.tsx`):
```ts
const isFullColor =
environment.widgetRenderingMode == null || environment.widgetRenderingMode === 'fullColor';
```
In tinted/clear modes the gradient is skipped and the existing containerBackground shows through, so text stays readable. Full-color mode is unchanged.
## Example

# Add `with-widgets` example (expo-widgets)
## What
Adds a new `with-widgets` example demonstrating how to build an iOS home
screen widget with
[`expo-widgets`](https://docs.expo.dev/versions/latest/sdk/widgets/) and
update its data from the app.
## Highlights
- **`widgets/MyWidget.tsx`** — the widget UI, written entirely in
TypeScript using
[`@expo/ui`](https://docs.expo.dev/versions/latest/sdk/ui/) SwiftUI
primitives with the `'widget'` directive. The background layers a
`linearGradient`\-filled `Rectangle` with a grid image in a `ZStack`,
clipped with
`clipShape('containerRelativeShape')`.
- **`App.tsx`** — an app screen that pushes new data to the widget via
`updateSnapshot`. Includes an `ensureImageInSharedStorage` helper that
copies the logo/grid assets into `widgetsDirectory` (the shared app
group container), since widgets run in a separate process and can't read
the app's asset bundle.
- **`app.json`** — `expo-widgets` config plugin setup registering the
widget with `systemSmall`/`systemMedium` families.
- **README** with setup instructions and notes, including the "Launch
with Expo" badge.
## Notes
- Targets SDK 56 (`expo@^56.0.4`, `expo-widgets@~56.0.17`).
- iOS only — requires a development build (not supported in Expo Go)
## How to test
1. `cd with-widgets && yarn`
2. `yarn ios`
3. Add **My Widget** to the home screen, then tap the button in the app
and watch the widget update.
Ran the following scripts locally, left `with-router-tv` and `with-tv`
as-is, @douglowder already took care of that in #686.
```bash
export EXPO_PACKAGE_MANAGER=bun
CI=true bash ./upgrade-dependencies.sh
```
My personal dom components demo is a better example of the best you can
get with shadcn and DOM components
https://github.com/EvanBacon/expo-dom-components-example so I'm updating
the example to be a leaner version of it for use with Expo Agent.
PR fixes multiple issues in the with-skia example that prevent it from
working correctly on Web and developed on Windows.
Changes were tested on Windows using both npm and pnpm for Web and
Android.
It's my first time working with templates so any corrections are
welcome. Thank you!
## Fixes
**1. When creating a project with this example npm exits with code 1.**
Running `npm i` [email protected] asks for
react-native-worklets >= 0.7.0
Limiting react-native-reanimated to ~4.1.1 should be enough according to
[compatibility
table](https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/).
**2. Postinstall script is for Linux and fails on Windows.**
```mkdir public; cp $(node -p \"require.resolve('canvaskit-wasm/bin/full/canvaskit.wasm', { paths: [require.resolve('@shopify/react-native-skia')] })\") public/canvaskit.wasm```
Moved logic into a separate node.js script. It could be a nice use for `/scripts` folder but having is as standalone file works too. Inlining logic directly into postinstall would be difficult to maintain.
**3. Example app stops working after first browser page reload.**
```can't access property "RuntimeEffect", this.CanvasKit is undefined```
Simplified `async-skia.tsx`. Had to cache the promise to prevent Expo
from crashing after finishing bundling for Web.
`with-tv`:
- Update dependencies and README
`with-router-tv`:
- Update dependencies and README
- Move to the [revamped default project template](https://expo.dev/changelog/sdk-55-beta#revamped-default-project-template) for SDK 55, including the new native tabs
- Style and theme hooks to support different platforms and screen rotation
Should not be merged until SDK 55 GA version is published to NPM.
Upgraded @ai-sdk/openai, @ai-sdk/react, and ai dependencies to latest
major versions. Refactored chat API to use new message conversion, tool
schema, and streaming response methods. Updated chat component to use
new useChat API and simplified tool output rendering for weather and
temperature conversion.
…rror handling
- Update ImagePicker handling to support newer expo-image-picker
versions (v14+) which return an 'assets' array and 'canceled' property
instead of the legacy flat structure.
- Fixes crash where 'base64' was undefined, causing Google Vision API
'INVALID_ARGUMENT' errors.
- Add check for 'error' in Google Vision API response to gracefully
handle permissions/quota issues instead of unhandled promise rejection.
- Delete autoprefixer — now default in Expo CLI.
- Delete custom metro.config.js — package.json exports are now enabled
by default.
- Upgrade to latest RSD postcss config.
- Use `postcss.config.mjs`.
- Upgrade CSS directive `@stylex` -> `@react-strict-dom`.
- Remove `EXPO_USE_FAST_RESOLVER=1` in favor of fixed default version.
- Migrate `.stylex.ts` file to `.css.ts` file. Some strangeness here
that requires the fully qualified path to be imported.