React Native screen with Expo and TypeScript, covering every state

Generate a React Native and TypeScript mobile screen with loading, empty, error and offline states, an optimized list, accessibility, safe areas and tests with Testing Library. Designed for ChatGPT, Claude, Gemini and Microsoft Copilot. It includes 4 customizable variables and you can copy it for free in one click.

Intermediate · Code · Pending editorial review

Prompt

Act as a senior mobile developer specializing in React Native, Expo and TypeScript, with a focus on performance and accessibility on iOS and Android.

Context:
- Screen purpose and user actions: {{screen}}
- Data source (endpoint, response shape, authentication): {{data}}
- Navigation library: {{navigation}}
- Visual style and libraries already in the project: {{style}}

Deliverables:
1. File structure: screen, child components, data hook and types.
2. TypeScript types for the API response and props; no any.
3. A data hook with loading, error, retry, pull-to-refresh and cancellation when the screen unmounts. If the project already uses a data-fetching library, adapt to it; if not, explain when one would be worth adding.
4. The complete screen with clear states: loading (skeleton), empty with a call to action, error with a retry button, and offline.
5. Lists with FlatList or an optimized equivalent: stable keyExtractor, memoized items, pagination or infinite scroll if relevant.
6. Accessibility: accessibilityLabel and accessibilityRole, minimum touch target sizes, dynamic type support and correct reading with VoiceOver and TalkBack.
7. Adaptive layout: SafeAreaView or insets, keyboard handling (KeyboardAvoidingView if there are forms), dark mode and iOS/Android differences.
8. Tests with React Native Testing Library for loading, error and success states, with the API mocked.

Constraints:
- Do not invent endpoints or fields: if the response shape is missing, use a type marked [FILL IN] and ask me.
- Do not add new dependencies without justifying why and offering the no-dependency alternative.
- If the screen or flow is unclear, ask me before writing the code.

Format: numbered sections, one code block per file and brief notes on decisions.

How to use it

Paste a real sample of your API's JSON response and list the libraries you already use. Test the screen on one iOS and one Android device, with airplane mode on and the font size at maximum.

Usage example

Screen: the user’s order list with a status filter and detail on tap · Data: paginated GET /orders with a token · Navigation: Expo Router · Style: StyleSheet with brand colors.

Sample output

3. Data hook — hooks/useRecipes.ts

import { useCallback, useEffect, useRef, useState } from 'react';

export type Recipe = { id: string; title: string; image: string; minutes: number }; // id type: [FILL IN]
type RecipesResponse = { items: Recipe[]; total: number };
type Status = 'loading' | 'error' | 'success';

const API_URL = process.env.EXPO_PUBLIC_API_URL;

export function useRecipes(search: string) {
  const [recipes, setRecipes] = useState<Recipe[]>([]);
  const [status, setStatus] = useState<Status>('loading');
  const [refreshing, setRefreshing] = useState(false);
  const controller = useRef<AbortController | null>(null);

  const load = useCallback(async (isRefresh = false) => {
    controller.current?.abort();                        // cancel the previous request
    const ctrl = new AbortController();
    controller.current = ctrl;
    if (isRefresh) setRefreshing(true); else setStatus('loading');
    try {
      // Search parameter name: [FILL IN]
      const params = new URLSearchParams({ page: '1', q: search });
      const res = await fetch(`${API_URL}/api/recipes?${params}`, { signal: ctrl.signal });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const data = (await res.json()) as RecipesResponse;
      setRecipes(data.items);
      setStatus('success');
    } catch {
      if (!ctrl.signal.aborted) setStatus('error');
    } finally {
      if (!ctrl.signal.aborted) setRefreshing(false);
    }
  }, [search]);

  useEffect(() => {
    load();
    return () => controller.current?.abort();           // when the screen unmounts
  }, [load]);

  return { recipes, status, refreshing, retry: () => load(), refresh: () => load(true) };
}

No new dependencies: once the app grows (cross-screen caching, infinite pagination), a data-fetching library would be worth adding. The screen uses status to show a skeleton, an error with a "Try again" button, or the FlatList…

Key facts

Category
Programming & development · Mobile apps
Output type
Code
Level
Intermediate
Designed for
ChatGPT, Claude, Gemini and Microsoft Copilot
Verified in
Pending editorial verification
Variables
Screen purpose, Data source, Navigation and Style and libraries
Language
English
Price
Free, no sign-up
Updated
Nov 7, 2026

Frequently asked questions

Does the code work in an app without Expo?

Mostly yes, since the components and hooks are plain React Native. Parts that use Expo modules, such as connectivity detection or fonts, will change; ask the model for the React Native CLI alternative.

Why so many states for one screen?

Because mobile networks fail often and a blank screen looks like a broken app. Showing loading, empty, error and offline states improves the experience and reduces bad reviews.

What is this prompt for?

Generate a React Native and TypeScript mobile screen with loading, empty, error and offline states, an optimized list, accessibility, safe areas and tests with Testing Library.

Which AI tools does it work with?

It is designed for ChatGPT, Claude, Gemini and Microsoft Copilot. We have not verified it in these tools yet, so results may vary between them.

How do I customize the prompt?

Click “Customize” and fill in the variables (Screen purpose, Data source, Navigation and Style and libraries). The text updates instantly and you can then copy it in one click. Values are stored only in your browser.

Do I need experience to use it?

It is intermediate: it helps to know the topic so you can provide good context and review the result critically.

Is this prompt free?

Yes. Every HomeCasa Prompts prompt is free, with no sign-up or subscription. You can also use them in professional projects.

Can I trust the AI output?

Treat it as a high-quality draft: always check data, figures and important claims before publishing or making decisions.

Related prompts