In questo tutorial, partiremo da una nuova React app React e passeremo allo sviluppo mobile nativo con Capacitor. Puoi anche aggiungere Capgo Native Navigation and Transitions per un feeling nativo, e usare tailwind-capacitor per le safe areas.
Capacitor ti permette di convertire facilmente la tua web app React in un'app mobile nativa, senza modifiche sostanziali o la necessità di imparare nuove skill come React Native.
Con pochi semplici passaggi, la maggior parte delle applicazioni React può essere trasformata in app mobile.
Questo tutorial ti guiderà nel processo, partendo da una nuova app React e integrando Capacitor per passare al mondo delle app mobile native. Puoi anche usare Capgo Native Navigation, Transitions e tailwind-capacitor per le safe areas.
Informazioni su Capacitor
CapacitorJS cambia le regole del gioco! Puoi integrarlo senza sforzo in qualsiasi progetto web: avvolgerà la tua applicazione in una webview nativa, generando automaticamente i progetti Xcode e Android Studio. Inoltre, i suoi plugin permettono di accedere alle funzionalità native del dispositivo, come la fotocamera, tramite un bridge JS.
Con Capacitor, otterrai una fantastica app mobile nativa senza configurazioni complicate o curve di apprendimento ripide. Il suo API leggero e le funzionalità ottimizzate lo rendono semplicissimo da integrare nel tuo progetto. Fidati, rimarrai stupito di quanto sia facile creare un'app nativa completa con Capacitor!
Preparazione della tua app React
Sebbene esistano vari modi per avviare applicazioni React, in questo tutorial utilizzeremo il metodo più semplice per ottenere un'applicazione React vuota:
npx create-react-app my-app
Per creare un'app mobile nativa, abbiamo bisogno di un export del nostro progetto. Quindi, aggiungiamo uno script semplice nel nostro package.json che possa essere utilizzato per buildare ed esportare il progetto React:
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
}
Ora puoi eseguire npm run build senza preoccupazioni; dovresti trovare una nuova cartella out nella root del tuo progetto.
Questa cartella verrà usata da Capacitor in seguito, ma per ora dobbiamo configurarla correttamente.
Aggiungere Capacitor alla tua app React
Per impacchettare un'app web in un container mobile nativo, dobbiamo seguire alcuni passaggi iniziali, ma poi basterà eseguire un singolo sync comando.
Per prima cosa, possiamo installare Capacitor CLI come dev dependency e poi configurarlo nel progetto. Durante il setup, puoi premere “invio” per accettare i valori predefiniti di name e bundle ID.
Successivamente, dobbiamo installare il pacchetto core e i pacchetti necessari per le piattaforme iOS e Android.
Infine, possiamo aggiungere le piattaforme e Capacitor creerà le cartelle per ogni piattaforma nella root del progetto:
# Install the Capacitor CLI locally
npm install -D @capacitor/cli
# Initialize Capacitor in your React project
npx cap init
# Install the required packages
npm install @capacitor/core @capacitor/ios @capacitor/android
# Add the native platforms
npx cap add ios
npx cap add android
A questo punto, dovresti essere in grado di osservare nuovi iOS e Android cartelle nel tuo progetto React.
Sono veri progetti nativi!
Per accedere al progetto Android in seguito, devi installare Android Studio. Per iOS, ti serve un Mac e dovresti installare Xcode.
Inoltre, dovresti trovare un file capacitor.config.ts nel tuo progetto, che contiene alcune impostazioni fondamentali di Capacitor utilizzate durante la sync. L'unica cosa a cui prestare attenzione è il webDir, che deve puntare al risultato del tuo comando di build. Attualmente non è corretto.
Per risolvere, apri il capacitor.config.json file e aggiorna il webDir:
{
"appId": "com.example.app",
"appName": "my-app",
"webDir": "out",
"bundledWebRuntime": false
}
Puoi provarlo eseguendo i seguenti comandi:
npm run build
npx cap sync
Il primo comando npm run build effettuerà semplicemente la build del tuo progetto React ed esporterà la build statica.
Mentre il secondo comando npx cap sync sincronizzerà tutti i code web nelle posizioni corrette delle piattaforme native per visualizzarli nell'app.
Inoltre, il comando sync potrebbe aggiornare le piattaforme native e installare plugin, quindi quando installi un nuovo plugin Capacitor è il momento di eseguire npx cap sync di nuovo.
Senza accorgertene, hai finito: ora vediamo l'app su un dispositivo!
Build e deploy di app native
Per sviluppare app iOS, devi avere Xcode installato, mentre per le app Android serve Android Studio installato. Inoltre, se vuoi distribuire l'app sugli store, devi iscriverti all'Apple Developer Program per iOS e alla Google Play Console per Android.
Se sei alle prime armi con lo sviluppo mobile nativo, puoi usare Capacitor CLI per aprire facilmente entrambi i progetti nativi:
npx cap open ios
npx cap open android
Una volta configurati i progetti nativi, il deploy dell'app su un dispositivo connesso è semplicissimo. In Android Studio, ti basta attendere che tutto sia pronto e potrai fare il deploy senza cambiare impostazioni. Ecco un esempio:

In Xcode, devi configurare il tuo account di signing per distribuire l'app su un dispositivo reale invece che solo sul simulatore. Se non l'hai mai fatto, Xcode ti guida nel processo (ma anche qui devi essere iscritto al Developer Program). Dopo, ti basta premere play per eseguire l'app sul dispositivo connesso, che puoi selezionare in alto. Ecco un esempio:

Congratulazioni! Hai distribuito con successo la tua web app React su un dispositivo mobile. Ecco un esempio:
Ma aspetta, c'è anche un modo più veloce per farlo durante lo sviluppo...
Capacitor Live Reload
A questo punto sarai probabilmente abituato ad avere l'hot reload con tutti i framework moderni, e la buona notizia è che puoi avere la stessa funzionalità su un dispositivo mobile con il minimo sforzo!
Abilita l'accesso alla tua applicazione ospitata localmente con live reload sulla tua rete facendo caricare i contenuti all'app Capacitor tramite l'URL specifico.
Il primo passo è individuare il tuo indirizzo IP locale. Se usi un Mac, puoi trovarlo eseguendo questo comando nel terminale:
ipconfig getifaddr en0
Su Windows, esegui:
ipconfig
Poi cerca l'indirizzo IPv4.
Possiamo istruire Capacitor a caricare l'app direttamente dal server aggiungendo un'altra voce al nostro capacitor.config.ts file:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'my-app',
webDir: 'out',
bundledWebRuntime: false,
server: {
url: 'http://192.168.x.xx:3000',
cleartext: true
}
};
export default config;
Assicurati di usare l'IP e la porta corretti, in questo esempio ho usato la porta predefinita di React.
Ora possiamo applicare queste modifiche copiandole nel nostro progetto nativo:
npx cap copy
L'oggetto copy il comando è simile a sync, ma copierà solo le modifiche apportate alla cartella web e alla configurazione, senza aggiornare il progetto nativo.
Ora puoi distribuire la tua app un'ultima volta tramite Android Studio o Xcode. Successivamente, se modifichi qualcosa nella tua app React, l'app si ricaricherà automaticamente e mostrerà le modifiche!
Tieni presente che se installi nuovi plugin come la fotocamera, è comunque necessario un rebuild del progetto nativo. Questo perché i file nativi vengono modificati e l'operazione non può avvenire on the fly.
Nota che dovresti usare l'IP e la porta corretti nella configurazione. Il blocco code sopra mostra la porta React predefinita a scopo dimostrativo.
Utilizzo dei Capacitor Plugin
Vediamo come usare un plugin Capacitor in azione, come abbiamo menzionato in precedenza. Per farlo, possiamo installare un plugin piuttosto semplice eseguendo:
npm i @capacitor/share
Non c'è nulla di complicato nel Plugin di condivisione, ma apre comunque la dialog nativa di condivisione! Per farlo, ora basta importare il pacchetto e chiamare la share() funzione dalla nostra app. Cambiamo src/App.js in questo modo:
import React from 'react';
import { Share } from '@capacitor/share';
function App() {
const share = async () => {
await Share.share({
title: 'Open Youtube',
text: 'Check new video on youtube',
url: 'https://www.youtube.com',
dialogTitle: 'Share with friends'
});
};
return (
<div>
<h1>Welcome to React and Capacitor!</h1>
<p>
<h2>Cool channel</h2>
<button onClick={() => share()}>Share now!</button>
</p>
</div>
);
}
export default App;
Come detto prima, quando installi nuovi plugin, devi eseguire un'operazione di sync e poi ridistribuire l'app sul dispositivo. Per farlo, esegui questo comando:
npx cap sync
Dopo aver premuto il tasto, potrai vedere la splendida dialog nativa di condivisione in azione!
In seguito, puoi rendere l'app più nativa su iOS e Android con la navigazione e le transizioni Capgo, risolvendo i comuni problemi di layout su iOS come l'overflow orizzontale o le safe area tagliate.
UI nativa con Capgo Native Navigation e Transitions
Ho lavorato per anni con Ionic per creare app cross-platform, ma integrarlo con React è complicato e raramente ne vale la pena se hai già Tailwind CSS.
Per un feeling mobile nativo in un'app React + Capacitor, usa i plugin Capgo invece di UI kit solo web come Konsta UI:
- @capgo/capacitor-native-navigation — navbar nativa, tab bar Liquid Glass su iOS e stile tab bar sfocata su Android. Il tuo React router gestisce lo stato delle rotte; il plugin gestisce la UI nativa.
- @capgo/capacitor-transitions — transizioni di pagina in stile Ionic e swipe-back laterale su iOS nel layer WebView, senza dover usare Ionic UI.
Installa entrambi:
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
Configura la navigazione nativa con la modalità CSS inset, così il contenuto web rispetta le barre native:
import { NativeNavigation } from '@capgo/capacitor-native-navigation';
await NativeNavigation.configure({
contentInsetMode: 'css',
animationDuration: 360,
glass: {
effect: 'liquidGlass',
},
});
Renderizza una tab bar Liquid Glass (iOS usa il rendering di sistema; Android usa un backdrop WebView sfocato):
await NativeNavigation.setTabbar({
selectedId: 'home',
labelVisibilityMode: 'labeled',
icons: true,
colors: { dynamic: true },
tabs: [
{ id: 'home', title: 'Home', icon: { svg: '...' } },
{ id: 'settings', title: 'Settings', icon: { svg: '...' } },
],
});
await NativeNavigation.addListener('tabSelect', ({ id }) => {
navigate(`/${id}`);
});
Aggiungi transizioni di pagina native nel tuo app shell:
import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/react';
initTransitions({ platform: 'auto' });
export function AppShell() {
const navigate = useNavigate();
const outletRef = useRef<HTMLElement>(null);
useEffect(() => {
if (outletRef.current) {
setupRouterOutlet(outletRef.current, { platform: 'auto', swipeGesture: 'auto' });
}
}, []);
const openSettings = () => {
setDirection('forward');
navigate('/settings');
};
return <cap-router-outlet ref={outletRef}>{/* routes */}</cap-router-outlet>;
}
Avvolgi le pagine roteate in cap-router-outlet, cap-page, e cap-content, e chiama setDirection('forward') o setDirection('back') prima di navigare. Non duplicare header o footer web quando la navigazione nativa gestisce quelle superfici.
Guarda le guide complete: Usare @capgo/capacitor-native-navigation e Usare @capgo/capacitor-transitions.
Safe areas con Tailwind
Per le safe area del dispositivo in Tailwind CSS, usa @capgo/tailwind-capacitor (pubblicato come tailwind-capacitor su npm. Fornisce safe-areas utility e altri plugin Tailwind compatibili con Capacitor:
bun add -D tailwind-capacitor
In src/index.css:
@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";
Usa utility come pt-safe, pb-safe, e px-safe invece di inserire manualmente env(safe-area-inset-*) a mano. Il progetto è in attivo sviluppo — se manca qualcosa per il tuo setup React, apri una PR su GitHub.
Risolvere problemi di layout su iOS (Viewport, Safe Area e Overflow orizzontale)
Se i contenuti appaiono tagliati, spostati o con scroll orizzontale su iOS, aggiungere solo overflow-x: hidden o modificare il tag viewport di solito non basta. Segui questi controlli in ordine.
Assicurati che il meta tag viewport sia applicato correttamente
Aggiungi il meta tag viewport in index.html all'interno di <head>:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
Gestisci la safe area di iOS da un unico wrapper root
Crea un unico app shell e applica il padding della safe area lì — non in vari componenti annidati:
html,
body,
#root {
width: 100%;
min-height: 100%;
margin: 0;
padding: 0;
overflow-x: hidden;
}
* {
box-sizing: border-box;
}
.app-shell {
min-height: 100dvh;
width: 100%;
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
Avvolgi tutto il contenuto della pagina in .app-shell. Il padding della safe-area duplicato in header, modal e layout wrapper spesso fa sembrare l'interfaccia tagliata o troppo grande.
Con @capgo/tailwind-capacitor, puoi gestire lo stesso padding con utility come pt-safe pb-safe px-safe su quel singolo shell.
Imposta Capacitor iOS contentInset a never primo
In capacitor.config.ts, preferisci l'inset nativo disabilitato e lascia che il CSS (o la Native Navigation) contentInsetMode: 'css') gestisca la safe area:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'dist',
ios: {
contentInset: 'never',
},
};
Mescolare l'automatic content inset di Capacitor con il padding env(safe-area-inset-*) CSS è una causa comune di spaziature doppie.
Trova l'elemento che causa l'overflow
Il colpevole di solito è un elemento che usa 100vw, Tailwind w-screen, una larghezza fissa in pixel o un grande min-width.
In Safari Web Inspector, esegui:
[...document.querySelectorAll('*')]
.filter(el => el.scrollWidth > document.documentElement.clientWidth)
.map(el => ({
el,
tag: el.tagName,
class: el.className,
scrollWidth: el.scrollWidth,
clientWidth: document.documentElement.clientWidth,
}));
Con Tailwind, sostituisci w-screen con w-full quando possibile. Molti problemi di overflow orizzontale derivano da 100vw / w-screen, padding della safe-area duplicato o un contenitore a larghezza fissa — non dal meta tag viewport stesso."
Conclusione
Capacitor è un'ottima opzione per creare applicazioni native partendo da un progetto web esistente, offrendo un modo semplice per condividere code e mantenere una UI coerente.
E con l'aggiunta di Capgo, è ancora più facile aggiungere i Live Update alla tua app, garantendo agli utenti l'accesso immediato alle ultime funzionalità e bug fix.
Se vuoi imparare come aggiungere Capgo alla tua app React, dai un'occhiata al prossimo articolo:
Continua il percorso: Creare App Mobile con React e Capacitor
Se stai usando Creare App Mobile con React e Capacitor per pianificare l'automazione CI/CD, connettilo con CI/CD Capgo per il workflow del prodotto in Capgo CI/CD, Capgo Native Build per il workflow del prodotto in Capgo Native Builds, Integrazioni Capgo per il workflow del prodotto in Integrazioni Capgo, Integrazione CI/CD per i dettagli di implementazione nell'integrazione CI/CD, e Integrazione GitHub Actions per i dettagli di implementazione nell'integrazione GitHub Actions.