A modern, production-ready starter template for building Solana dApps with the Phantom Connect SDK.
- ⚡️ Next.js 16 - Latest App Router with React Server Components
- 👻 Phantom Connect SDK - Integrated wallet with built-in modal UI
- 🔑 OAuth Support - Google, Apple, and Phantom Login authentication
- 💸 Transaction Demo - Sign message & send SOL examples
- 🎨 Tailwind CSS - Utility-first styling with custom design tokens
- 🌗 Dark Mode - Built-in dark mode support
- 📱 Responsive - Mobile-first responsive design
- 🔐 TypeScript - Full type safety
- Next.js - React framework
- @phantom/react-sdk - Phantom Connect SDK for React
- @phantom/browser-sdk - Phantom Connect SDK core
- @solana/web3.js - Solana JavaScript API
- Tailwind CSS - Utility-first CSS framework
- Node.js 18+
- pnpm (recommended) or npm
- Clone the repository:
git clone <your-repo-url>
cd phantom-embedded-react-starter- Install dependencies:
pnpm install
# or
npm install- Copy the environment variables:
cp .env.example .env.local- Update the environment variables in
.env.localwith your configuration.
Run the development server:
pnpm dev
# or
npm run devOpen http://localhost:3000 in your browser to see the app.
Build the application for production:
pnpm build
# or
npm run buildpnpm start
# or
npm startphantom-embedded-react-starter/
├── public/ # Static assets
│ └── phantom-logo.png
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── auth/
│ │ │ └── callback/
│ │ │ └── page.tsx # OAuth callback handler
│ │ ├── globals.css # Global styles with design tokens
│ │ ├── layout.tsx # Root layout
│ │ └── page.tsx # Home page
│ ├── components/ # React components
│ │ ├── ConnectWalletButton.tsx # Main wallet connection UI
│ │ ├── TransactionDemo.tsx # Sign message & send SOL demo
│ │ ├── ThemeToggle.tsx # Dark/light mode toggle
│ │ └── icons/ # Icon components
│ └── provider/
│ ├── ConnectionProvider.tsx # PhantomProvider wrapper
│ └── ThemeProvider.tsx # Theme context
├── .env.example # Environment variables template
├── next.config.js # Next.js configuration
└── tsconfig.json # TypeScript configuration
This starter uses a custom design token system for consistent theming:
- Color Tokens: Defined in
globals.cssusing CSS variables - Tailwind Integration: Design tokens mapped to Tailwind utilities
- Dark Mode: Automatic dark mode support via
prefers-color-scheme
--color-brand: Primary brand color--color-ink: Primary text color--color-paper: Background color- Additional semantic colors for states (success, warning, info)
The SDK is configured in src/provider/ConnectionProvider.tsx:
<PhantomProvider
config={{
appId: "your-app-id", // From Phantom Portal
addressTypes: [AddressType.solana], // Supported chains
providers: ["google", "apple", "phantom", "injected"],
authOptions: {
redirectUrl: "https://yourapp.com/auth/callback", // Required for OAuth
},
}}
theme={darkTheme}
appName="Your App Name"
appIcon="/your-icon.png"
>The /auth/callback page handles OAuth flow automatically. The PhantomProvider
processes the callback parameters when the page loads:
import { usePhantom } from "@phantom/react-sdk";
function AuthCallbackPage() {
const { isConnected, isLoading, connectError } = usePhantom();
// Redirect once connected
useEffect(() => {
if (isConnected) router.push("/");
}, [isConnected]);
if (connectError) return <ErrorUI />;
return <LoadingUI />;
}For embedded wallets (Google/Apple OAuth), use signAndSendTransaction:
import { useSolana } from "@phantom/react-sdk";
function MyComponent() {
const { solana, isAvailable } = useSolana();
const handleTransaction = async (transaction) => {
// Always check availability before calling
if (!isAvailable || !solana?.signAndSendTransaction) {
console.error("Solana provider not available");
return;
}
const result = await solana.signAndSendTransaction(transaction);
console.log("TX hash:", result.hash);
};
}Note: Embedded wallets do NOT support
signTransactionorsignAllTransactions. UsesignAndSendTransactionwhich signs and broadcasts in a single step.
- Go to Phantom Portal
- Create/select your app
- Copy your App ID
- Add your redirect URLs to the allowlist (e.g.,
http://localhost:3000/auth/callback)
| Variable | Description | Required |
|---|---|---|
NEXT_PUBLIC_PHANTOM_APP_ID |
App ID from Phantom Portal | Yes (for OAuth) |
NEXT_PUBLIC_SOLANA_RPC_URL |
Custom Solana RPC URL | No |
NEXT_PUBLIC_APP_URL |
Your app's URL (for OAuth callback) | No |
See .env.example for the template.
ISC
- Phantom React SDK - SDK documentation
- Sign & Send Transactions - Transaction signing guide
- Connect Flow - OAuth connection setup
- Phantom Portal - App configuration
- Next.js Documentation
- Solana Web3.js Documentation