laravel/react-starter-kit
Modern Laravel + React starter kit powered by Inertia. Includes React 19, TypeScript, Tailwind, shadcn/ui and Radix UI components, plus fast Vite builds. Ideal for SPA-like apps using classic Laravel routing and controllers.
Installation
composer create-project laravel/react-starter-kit my-app
cd my-app
npm install
npm run dev
php artisan serve
First Use Case: Create a React Page
php artisan inertia:page Dashboard
resources/js/Pages/Dashboard.tsx and its corresponding controller (app/Http/Controllers/DashboardController.php).Key Directories to Explore
resources/js/ – React/TypeScript/Vite entry point.resources/js/Pages/ – Inertia page components.resources/views/app.blade.php – Root Blade template (handles Inertia’s <app> tag).vite.config.ts – Vite configuration (optimizations, plugins).Server-Side Routing with React
routes/web.php using Inertia::render():
Route::get('/dashboard', [DashboardController::class, 'index']);
// Dashboard.tsx
const { user } = props;
State Management
// stores/auth.ts
import { create } from 'zustand';
type AuthState = { user: User | null };
export const useAuthStore = create<AuthState>((set) => ({ user: null }));
const user = useAuthStore((state) => state.user);
API Calls
resources/js/api.ts):
// Example: Fetch user data
const response = await api.get('/api/user');
shadcn/ui Integration
npx shadcn-ui@latest add button
tsconfig.json via paths).Tailwind Utilities
<div className="bg-blue-500 hover:bg-blue-600 transition-colors">
Hover me
</div>
Form Handling
import { useForm } from 'react-hook-form';
const { register, handleSubmit } = useForm();
Testing
resources/js/tests/).phpunit.xml).npm run dev/build instead of mix.PageProps for custom props:
interface DashboardProps extends PageProps {
stats: { users: number; posts: number };
}
.env for both Laravel and Vite (prefix with VITE_ for client-side access):
VITE_APP_API_URL=/api
Access in React:
const apiUrl = import.meta.env.VITE_APP_API_URL;
Inertia Page Caching
npm run build
vite.config.ts:
server: { hmr: { clientPort: 2999 } },
TypeScript Errors
resources/js/shims-vite.d.ts includes all global types (e.g., import.meta.env).npx shadcn-ui@latest add [component]
CSRF Token Mismatch
csrf-token meta tag, ensure it’s included in resources/views/app.blade.php:
@csrf
<meta name="csrf-token" content="{{ csrf_token() }}">
Vite Public Assets
public/ and reference them via:
<img src="/images/logo.png" alt="Logo" />
Zustand Persistence
localStorage manually if needed:
const useAuthStore = create<AuthState>()((set) => ({
user: JSON.parse(localStorage.getItem('user') || 'null'),
}));
Inertia warnings (e.g., missing page components).http://localhost:5173 (default Vite port).tail -f storage/logs/laravel.log
Custom Vite Plugins
Add plugins in vite.config.ts:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({
plugins: [
laravel({ input: ['resources/js/app.tsx'], refresh: true }),
VitePWA({ strategies: 'injectManifest' }),
],
});
Laravel Service Providers
Extend AppServiceProvider for global React props:
public function boot()
{
Inertia::share([
'auth' => fn () => auth()->user(),
'settings' => config('app.settings'),
]);
}
Tailwind Customization
Modify tailwind.config.js:
module.exports = {
content: [
'./resources/js/**/*.{ts,tsx}',
'./resources/views/**/*.blade.php',
],
theme: {
extend: {
colors: {
primary: '#3b82f6',
},
},
},
};
React Router Integration
Use react-router-dom alongside Inertia for client-side navigation (advanced):
import { BrowserRouter, Routes, Route } from 'react-router-dom';
// Wrap app in resources/js/app.tsx
Monorepo Support
For large projects, eject Vite config and use pnpm/yarn workspaces to share dependencies between Laravel and React.
How can I help you explore Laravel packages today?