Dalam tutorial ini, kita akan mulai dengan React app baru dan beralih ke pengembangan mobile native menggunakan Capacitor. Anda juga bisa menambahkan Capgo Native Navigation and Transitions agar terasa seperti aplikasi native, serta menggunakan tailwind-capacitor untuk safe area.
Capacitor memungkinkan Anda dengan mudah mengubah aplikasi web React menjadi aplikasi mobile native tanpa modifikasi signifikan atau mempelajari skill baru seperti React Native.
Hanya dengan beberapa langkah mudah, sebagian besar aplikasi React bisa diubah menjadi aplikasi mobile.
Tutorial ini akan memandu Anda melalui prosesnya, mulai dari aplikasi React baru hingga menyertakan Capacitor untuk masuk ke ranah aplikasi mobile native. Anda juga bisa menggunakan Capgo Native Navigation, Transitions, dan tailwind-capacitor untuk safe areas.
Tentang Capacitor
CapacitorJS adalah game-changer! Anda bisa dengan mudah memasukkannya ke proyek web apa pun, dan ia akan membungkus aplikasi Anda ke dalam native webview, sekaligus membuatkan proyek native Xcode dan Android Studio untuk Anda. Selain itu, plugin-nya menyediakan akses ke fitur native perangkat seperti kamera melalui JS bridge.
Dengan Capacitor, Anda mendapatkan aplikasi mobile native yang luar biasa tanpa setup rumit atau learning curve yang tinggi. API yang ramping dan fungsionalitasnya yang efisien membuatnya sangat mudah diintegrasikan ke proyek Anda. Percayalah, Anda akan takjub betapa mudahnya membuat aplikasi native yang berfungsi penuh dengan Capacitor!
Menyiapkan React App Anda
Meskipun ada berbagai cara untuk memulai aplikasi React, mari kita gunakan cara termudah dalam tutorial ini yang menyediakan aplikasi React kosong:
npx create-react-app my-app
Untuk membuat aplikasi mobile native, kita memerlukan sebuah export dari proyek kita. Jadi, mari kita tambahkan script sederhana di package.json yang dapat digunakan untuk build dan export proyek React:
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
}
Sekarang Anda bisa menjalankan npm run build tanpa perlu khawatir, dan Anda akan melihat folder out yang baru di root proyek Anda.
Folder ini akan digunakan oleh Capacitor nanti, tapi untuk saat ini, kita harus mengaturnya dengan benar.
Menambahkan Capacitor ke React App Anda
Untuk membungkus web app ke dalam container mobile native, kita perlu mengikuti beberapa langkah awal, namun setelah itu cukup dengan satu sync command.
Pertama, kita bisa menginstal Capacitor CLI sebagai dev dependency, lalu mengaturnya di dalam proyek. Saat setup, Anda bisa menekan “enter” untuk menerima nilai default name dan bundle ID.
Berikutnya, kita perlu menginstal package inti serta package yang relevan untuk platform iOS dan Android.
Terakhir, kita bisa menambahkan platform, dan Capacitor akan membuat folder untuk setiap platform di root proyek kita:
# 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
Pada tahap ini, Anda seharusnya sudah bisa melihat iOS dan android folder di proyek React Anda.
Itu adalah proyek native sungguhan!
Untuk mengakses proyek Android nantinya, Anda harus menginstal Android Studio. Untuk iOS, Anda butuh Mac dan harus menginstal Xcode.
Selain itu, Anda akan menemukan file capacitor.config.ts di proyek Anda, yang berisi beberapa pengaturan dasar Capacitor yang digunakan saat sinkronisasi. Satu hal yang perlu Anda perhatikan adalah webDir, yang harus mengarah ke hasil perintah build Anda. Saat ini, nilainya tidak tepat.
Untuk memperbaikinya, buka file capacitor.config.json file dan perbarui webDir:
{
"appId": "com.example.app",
"appName": "my-app",
"webDir": "out",
"bundledWebRuntime": false
}
Anda bisa mencobanya dengan menjalankan perintah berikut:
npm run build
npx cap sync
Perintah pertama npm run build hanya akan melakukan build pada proyek React Anda dan mengekspor static build.
Sedangkan perintah kedua npx cap sync akan menyinkronkan semua web code ke tempat yang tepat di platform native agar bisa ditampilkan di aplikasi.
Selain itu, perintah sync mungkin akan memperbarui platform native dan menginstal plugin, jadi saat Anda menginstal Plugin Capacitor saatnya menjalankan npx cap sync lagi.
Tanpa terasa, Anda sudah selesai, sekarang mari kita coba aplikasinya di perangkat!
Build dan Deploy aplikasi native
Untuk membuat aplikasi iOS, Anda perlu menginstal Xcode dan untuk aplikasi Android, Anda perlu menginstal Android Studio terinstal. Selain itu, jika Anda berencana mendistribusikan aplikasi di app store, Anda perlu mendaftar di Apple Developer Program untuk iOS dan Google Play Console untuk Android.
Jika Anda baru mengenal pengembangan mobile native, Anda bisa menggunakan Capacitor CLI untuk membuka kedua proyek native dengan mudah:
npx cap open ios
npx cap open android
Setelah proyek native siap, deploy aplikasi ke perangkat yang terhubung sangatlah mudah. Di Android Studio, Anda cukup menunggu hingga semuanya siap, lalu deploy aplikasi ke perangkat tanpa mengubah pengaturan apa pun. Berikut contohnya:

Di Xcode, Anda perlu mengatur signing account untuk deploy aplikasi ke perangkat asli, bukan sekadar simulator. Jika belum pernah melakukannya, Xcode akan memandu prosesnya (tapi sekali lagi, Anda harus terdaftar di Developer Program). Setelah itu, Anda cukup tekan play untuk menjalankan aplikasi di perangkat yang terhubung, yang bisa dipilih di bagian atas. Berikut contohnya:

Selamat! Anda telah berhasil men-deploy React web app ke perangkat mobile. Berikut contohnya:
Tapi tunggu dulu, ada cara yang lebih cepat untuk melakukan ini saat development…
Capacitor Live Reload
Saat ini, Anda mungkin sudah terbiasa dengan hot reload di semua framework modern, dan kabar baiknya adalah Anda bisa mendapatkan fitur yang sama di perangkat mobile dengan usaha minimal!
Aktifkan akses ke aplikasi lokal Anda dengan live reload di jaringan Anda dengan membuat aplikasi Capacitor memuat konten dari URL tertentu.
Langkah pertama adalah mencari tahu alamat IP lokal Anda. Jika menggunakan Mac, Anda bisa mengetahuinya dengan menjalankan perintah berikut di terminal:
ipconfig getifaddr en0
Di Windows, jalankan:
ipconfig
Lalu cari alamat IPv4.
Kita bisa menginstruksikan Capacitor untuk memuat aplikasi langsung dari server dengan menambahkan entri lain ke 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;
Pastikan untuk menggunakan IP dan port yang benar, saya menggunakan port default React dalam contoh ini.
Sekarang, kita bisa menerapkan perubahan ini dengan menyalinnya ke proyek native kita:
npx cap copy
Panduan copy perintahnya mirip dengan sync, tapi ini hanya akan menyalin perubahan yang ada di folder web dan konfigurasi, tanpa memperbarui native project.
Sekarang Anda bisa deploy aplikasi sekali lagi melalui Android Studio atau Xcode. Setelah itu, jika Anda mengubah sesuatu di React app Anda, aplikasi akan otomatis reload dan menampilkan perubahannya!
Perlu diingat bahwa jika Anda menginstal plugin baru seperti kamera, Anda tetap perlu melakukan rebuild pada native project. Ini karena file native berubah, dan tidak bisa dilakukan secara on the fly.
Pastikan Anda menggunakan IP dan port yang benar di konfigurasi Anda. Blok code di atas menunjukkan port default React untuk keperluan demonstrasi.
Menggunakan Plugin Capacitor
Mari kita lihat cara menggunakan plugin Capacitor secara langsung, yang sudah kita sebutkan sebelumnya. Untuk melakukannya, kita bisa menginstal plugin yang cukup simpel dengan menjalankan:
npm i @capacitor/share
Tidak ada yang rumit dari Plugin share, tapi tetap memunculkan dialog share native! Untuk ini, kita hanya perlu mengimpor package dan memanggil share() function dari aplikasi kita. Mari ubah src/App.js menjadi:
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;
Seperti yang disebutkan sebelumnya, saat menginstal plugin baru, kita perlu melakukan operasi sync lalu redeploy aplikasi ke perangkat. Untuk melakukannya, jalankan perintah berikut:
npx cap sync
Setelah menekan tombol, Anda bisa melihat dialog share native yang keren langsung bekerja!
Selanjutnya, Anda bisa membuat aplikasi terasa lebih native di iOS dan Android dengan navigasi dan transisi Capgo, serta memperbaiki masalah layout iOS umum yang menyebabkan horizontal overflow atau area safe area terpotong.
UI yang terasa native dengan Native Navigation dan Transitions dari Capgo
Saya telah bekerja bertahun-tahun dengan Ionic untuk membangun aplikasi lintas platform, namun mengintegrasikannya dengan React terasa kurang optimal dan jarang sepadan jika Anda sudah menggunakan Tailwind CSS.
Untuk mendapatkan feel mobile native pada aplikasi React + Capacitor, gunakan plugin Capgo alih-alih UI kit berbasis web seperti Konsta UI:
- @capgo/capacitor-native-navigation — navbar native, Liquid Glass tab bar di iOS, dan gaya tab bar blur di Android. React router Anda tetap mengelola route state; plugin yang menangani native chrome.
- @capgo/capacitor-transitions — transisi halaman ala Ionic dan fitur iOS edge swipe-back di layer WebView, tanpa harus memakai Ionic UI.
Install keduanya:
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
Konfigurasi navigasi native dengan mode inset CSS agar konten web menyesuaikan dengan bar native:
import { NativeNavigation } from '@capgo/capacitor-native-navigation';
await NativeNavigation.configure({
contentInsetMode: 'css',
animationDuration: 360,
glass: {
effect: 'liquidGlass',
},
});
Render Liquid Glass tab bar (iOS menggunakan rendering dari sistem; Android menggunakan backdrop WebView yang blur):
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}`);
});
Tambahkan transisi halaman native di app shell Anda:
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>;
}
Bungkus halaman yang di-route dengan cap-router-outlet, cap-page, dan cap-content, dan panggil setDirection('forward') atau setDirection('back') sebelum navigasi. Jangan duplikasi header atau footer web jika navigasi native sudah mengelola area tersebut.
Lihat panduan lengkapnya: Menggunakan @capgo/capacitor-native-navigation dan Menggunakan @capgo/capacitor-transitions.
Safe areas dengan Tailwind
Untuk device safe areas di Tailwind CSS, gunakan @capgo/tailwind-capacitor (diterbitkan sebagai tailwind-capacitor pada npm). Ini menyediakan safe-areas utilitas dan plugin Tailwind lain yang kompatibel dengan Capacitor:
bun add -D tailwind-capacitor
Di src/index.css:
@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";
Gunakan utilitas seperti pt-safe, pb-safe, dan px-safe daripada menyisipkan env(safe-area-inset-*) secara manual. Proyek ini dikembangkan secara aktif — jika ada yang kurang untuk setup React Anda, buka PR di GitHub.
Memperbaiki Masalah Layout iOS (Viewport, Safe Area, dan Horizontal Overflow)
Jika konten terlihat terpotong, bergeser, atau bisa di-scroll secara horizontal di iOS, menambahkan lebih banyak overflow-x: hidden atau hanya mengutak-atik tag viewport saja biasanya tidak memperbaikinya. Lakukan pemeriksaan ini secara berurutan.
Pastikan meta tag viewport diterapkan dengan benar
Tambahkan viewport meta tag di index.html di dalam <head>:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
Tangani iOS safe area hanya dari satu root wrapper
Buat satu app shell dan terapkan safe area padding di sana — bukan di beberapa komponen bersarang:
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);
}
Bungkus seluruh konten halaman di dalam .app-shell. Padding safe-area yang dobel di header, modal, dan wrapper layout sering membuat UI terlihat terpotong atau terlalu besar.
Dengan @capgo/tailwind-capacitor, Anda bisa menggunakan padding yang sama dengan utility seperti pt-safe pb-safe px-safe pada satu shell tersebut.
Atur Capacitor iOS contentInset ke never dulu
Di capacitor.config.ts, lebih baik nonaktifkan native inset dan biarkan CSS (atau Native Navigation’s contentInsetMode: 'css') mengatur safe area:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'dist',
ios: {
contentInset: 'never',
},
};
Mencampur automatic content inset dari Capacitor dengan CSS env(safe-area-inset-*) padding sering kali menjadi penyebab spasi ganda.
Temukan elemen yang benar-benar overflow
Penyebab umumnya adalah elemen yang menggunakan 100vw, Tailwind w-screen, lebar pixel tetap, atau ukuran besar min-width.
Di Safari Web Inspector, jalankan:
[...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,
}));
Dengan Tailwind, ganti w-screen dengan w-full jika memungkinkan. Banyak masalah overflow horizontal berasal dari 100vw / w-screen, duplikasi safe-area padding, atau container dengan lebar tetap — bukan dari viewport meta tag itu sendiri.
Kesimpulan
Capacitor adalah opsi luar biasa untuk membangun aplikasi native berbasis proyek web yang sudah ada, menawarkan cara simpel untuk berbagi code dan menjaga UI tetap konsisten.
Dan dengan tambahan Capgo, kini makin mudah menambahkan live updates ke aplikasi Anda, memastikan pengguna selalu mendapatkan fitur terbaru dan perbaikan bug.
Jika Anda ingin belajar cara menambahkan Capgo ke aplikasi React Anda, simak artikel berikut:
Lanjutkan dari Building Mobile Apps with React and Capacitor
Jika Anda menggunakan Membangun Aplikasi Mobile dengan React dan Capacitor untuk merencanakan otomatisasi CI/CD, hubungkan dengan CI/CD Capgo untuk workflow produk di Capgo CI/CD, Capgo Native Build untuk workflow produk di Capgo Native Builds, Integrasi Capgo untuk alur kerja produk di Integrasi Capgo, Integrasi CI/CD untuk detail implementasi di Integrasi CI/CD, dan Integrasi GitHub Actions untuk detail implementasi di Integrasi GitHub Actions.