skills/capacitor-react/SKILL.md
Guides the agent through Capacitor app development with React — project structure, hooks for native features, state management patterns, using Capacitor plugins in React components, and React-specific best practices. Do not use for Ionic Framework with React (use ionic-react), migrating or upgrading Capacitor apps or plugins, or non-React frameworks.
npx skillsauth add capawesome-team/skills capacitor-reactInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Develop Capacitor apps with React — project structure, hooks, state management, and React-specific patterns for accessing native device features.
package.json dependencies (react, react-dom, @capacitor/core), platforms (android/, ios/), build tools (vite.config.ts, next.config.js, webpack.config.js), and TypeScript usage. Only ask the user when something cannot be detected.Auto-detect the following by reading project files:
package.json dependencies and config files (vite.config.ts, next.config.js, remix.config.js).@capacitor/core version from package.json.react version from package.json.tsconfig.json exists and if .tsx files are used.android/, ios/).capacitor.config.ts or capacitor.config.json.package.json for redux, @reduxjs/toolkit, zustand, jotai, @tanstack/react-query, or similar.package.json for react-router-dom, @tanstack/react-router, or similar.A standard Capacitor React project follows this structure:
project-root/
├── android/ # Android native project (generated by Capacitor)
├── ios/ # iOS native project (generated by Capacitor)
├── public/
├── src/
│ ├── components/ # Reusable UI components
│ ├── hooks/ # Custom React hooks (including native feature hooks)
│ ├── pages/ # Page/route components
│ ├── services/ # Service modules for Capacitor plugin calls
│ ├── App.tsx # Root component
│ └── main.tsx # Entry point
├── capacitor.config.ts # Capacitor configuration
├── package.json
├── tsconfig.json
└── vite.config.ts # Or other bundler config
If the project does not follow this structure, adapt all guidance to the project's actual directory layout. Do not restructure the project unless the user explicitly asks.
Read references/plugin-usage-patterns.md for detailed patterns on how to use Capacitor plugins in React components and hooks.
Key principles:
useEffect for listeners — register and clean up Capacitor event listeners inside useEffect.Capacitor.isNativePlatform() or Capacitor.getPlatform() to guard platform-specific calls.Read references/custom-hooks.md for reusable custom hook patterns that wrap Capacitor plugins.
Custom hooks encapsulate native feature access and provide a React-idiomatic API. When the user needs to access a native feature from multiple components, create a custom hook in src/hooks/ (or wherever the project keeps hooks).
When the project uses a state management library, integrate native data as follows:
useState/useReducer to share native data across components.Do not recommend adding a state management library unless the user's requirements justify it.
If the project uses react-router-dom or another router:
appUrlOpen events from the @capacitor/app plugin inside a useEffect in the root component or a dedicated hook. Navigate programmatically using the router's useNavigate() hook.import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { App, URLOpenListenerEvent } from '@capacitor/app';
const useDeepLinks = () => {
const navigate = useNavigate();
useEffect(() => {
const listener = App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {
const path = new URL(event.url).pathname;
navigate(path);
});
return () => {
listener.then(handle => handle.remove());
};
}, [navigate]);
};
backButton event from the @capacitor/app plugin to handle Android hardware back button presses.import { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { App } from '@capacitor/app';
const useBackButton = () => {
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const listener = App.addListener('backButton', ({ canGoBack }) => {
if (canGoBack) {
navigate(-1);
} else {
App.exitApp();
}
});
return () => {
listener.then(handle => handle.remove());
};
}, [navigate, location]);
};
Use Capacitor.getPlatform() or Capacitor.isNativePlatform() to conditionally render components or apply platform-specific behavior:
import { Capacitor } from '@capacitor/core';
const MyComponent: React.FC = () => {
const platform = Capacitor.getPlatform(); // 'ios' | 'android' | 'web'
const isNative = Capacitor.isNativePlatform();
return (
<div>
{platform === 'ios' && <IOSSpecificComponent />}
{platform === 'android' && <AndroidSpecificComponent />}
{!isNative && <WebFallbackComponent />}
</div>
);
};
For reusable platform checks, create a utility or hook:
import { Capacitor } from '@capacitor/core';
export const usePlatform = () => {
return {
platform: Capacitor.getPlatform(),
isNative: Capacitor.isNativePlatform(),
isIOS: Capacitor.getPlatform() === 'ios',
isAndroid: Capacitor.getPlatform() === 'android',
isWeb: Capacitor.getPlatform() === 'web',
};
};
Use the @capacitor/app plugin to respond to app lifecycle events in React:
import { useEffect } from 'react';
import { App } from '@capacitor/app';
const useAppState = (onResume?: () => void, onPause?: () => void) => {
useEffect(() => {
const resumeListener = App.addListener('resume', () => {
onResume?.();
});
const pauseListener = App.addListener('pause', () => {
onPause?.();
});
return () => {
resumeListener.then(handle => handle.remove());
pauseListener.then(handle => handle.remove());
};
}, [onResume, onPause]);
};
Use this to refresh data when the app returns to the foreground, pause media, or save state when the app is backgrounded.
After implementing changes:
npm run build
npx cap sync
npx cap run android
npx cap run ios
For development with live reload:
npx cap run android --livereload --external
npx cap run ios --livereload --external
The --external flag makes the dev server accessible from the device/emulator. The --livereload flag enables automatic reloads when source files change.
npx cap sync was run after installing a plugin. Verify the plugin is listed in package.json dependencies.Capacitor is not defined: The @capacitor/core package must be installed. Run npm install @capacitor/core.Capacitor.isNativePlatform(). Many plugins have web implementations, but some (e.g., @capacitor/camera with native UI) only work on iOS/Android.useEffect that calls remove() on the listener handle. Failing to do so causes duplicate listeners on re-renders.useRef to hold the latest value, or add the state variable to the useEffect dependency array and re-register the listener.--external flag is used with npx cap run. Verify no firewall is blocking the dev server port.window.localStorage, navigator.geolocation) used without Capacitor alternatives. Use Capacitor plugins (@capacitor/preferences, @capacitor/geolocation) instead.ionic-react — Ionic Framework-specific React patterns (IonReactRouter, lifecycle hooks, overlay hooks) for apps using @ionic/react.capacitor-angular — Angular-specific patterns and best practices for Capacitor app development.capacitor-app-upgrades — Upgrade a Capacitor app to a newer major version.capacitor-plugins — Install, configure, and use Capacitor plugins from official and community sources.capacitor-push-notifications — Set up push notifications with Firebase Cloud Messaging in a Capacitor app.tools
Guides the agent through migrating Capacitor apps from discontinued Ionic Enterprise SDK plugins (Auth Connect, Identity Vault, Secure Storage) to their Capawesome alternatives (OAuth, Vault, Biometrics, Secure Preferences, SQLite). Covers dependency detection, side-by-side API mapping, code replacement, and platform-specific configuration for each plugin pair. Do not use for migrating Capacitor apps or plugins to a newer version, setting up Capawesome Cloud, or non-Capacitor mobile frameworks.
tools
Guides the agent through installing, configuring, and using Capacitor plugins from six sources — official Capacitor plugins, Capawesome plugins, Capacitor Community plugins, Capacitor Firebase plugins, Capacitor MLKit plugins, and RevenueCat plugins. Covers installation, platform-specific configuration (Android and iOS), and basic usage examples. Do not use for migrating Capacitor apps or plugins to a newer version, setting up Capacitor Live Updates, or non-Capacitor mobile frameworks.
tools
Guides the agent through Ionic Vue development patterns — project structure, Vue-specific Ionic components (IonPage, IonRouterOutlet, IonTabs), navigation with Vue Router and useIonRouter, Ionic lifecycle hooks (onIonViewWillEnter, onIonViewDidEnter, onIonViewWillLeave, onIonViewDidLeave), composable utilities (useIonRouter, useBackButton, useKeyboard), tab-based routing, lazy loading, platform detection with isPlatform, and troubleshooting common Vue-specific issues. Do not use for general Ionic component theming or CLI usage (use ionic-app-development), creating a new Ionic app (use ionic-app-creation), Capacitor-specific Vue patterns without Ionic (use capacitor-vue), upgrading Ionic versions (use ionic-app-upgrades), or non-Vue frameworks like Angular or React.
development
Guides the agent through Ionic Framework development with React — project structure, React-specific Ionic components, IonReactRouter and navigation patterns, Ionic lifecycle hooks (useIonViewWillEnter, useIonViewDidEnter, useIonViewWillLeave, useIonViewDidLeave), state management integration, and React-specific best practices for Ionic apps. Do not use for plain Capacitor React apps without Ionic (use capacitor-react), Ionic with Angular or Vue, creating a new Ionic app (use ionic-app-creation), upgrading Ionic to a newer version (use ionic-app-upgrades), or general Ionic component usage without React-specific context (use ionic-app-development).