React Starter Kit - v1.0.1
Getting Started
After installation, here's a 5-minute tour.
What's where
app/
├── Http/
│ ├── Controllers/
│ │ ├── Auth/ Login, register, password reset, etc.
│ │ ├── Settings/ Profile / Password / Appearance
│ │ └── Controller.php Base controller
│ ├── Middleware/
│ │ └── HandleInertiaRequests.php Shared props (auth, flash, etc.)
│ └── Requests/
│ ├── Auth/LoginRequest.php
│ └── Settings/{ProfileUpdate,PasswordUpdate}Request.php
├── Models/User.php
└── Console/Commands/OptionalPackagesCommand.php
resources/
├── css/app.css Tailwind + DaisyUI + tokens
├── js/
│ ├── app.tsx Inertia client entry
│ ├── ssr.tsx Inertia SSR entry
│ ├── components/AppLogo.tsx
│ ├── layouts/
│ │ ├── AppLayout.tsx Sidebar + mobile navbar + toast region
│ │ ├── AuthLayout.tsx Centered card for auth pages
│ │ └── SettingsLayout.tsx AppLayout + settings tabs sidebar
│ ├── lib/InertiaToastProvider.tsx Local copy bypassing adapter root-import bug
│ ├── pages/ Inertia pages (resolved by createInertiaApp)
│ ├── actions/ ⟵ generated by wayfinder
│ └── routes/ ⟵ generated by wayfinder
└── views/
└── app.blade.php Inertia root template
routes/
├── web.php Welcome, dashboard, settings
├── auth.php Login/register/forgot/reset/etc.
└── console.php
Add a new page
-
Add the route in
routes/web.php:Route::get('reports', function () { return Inertia::render('Reports', [ 'rows' => Report::latest()->get(), ]); })->middleware(['auth'])->name('reports'); -
Run
php artisan wayfinder:generate(or just keep the dev server running — the Vite plugin regenerates on save). -
Create
resources/js/pages/Reports.tsx:import { Head } from '@inertiajs/react'; import AppLayout from '@/layouts/AppLayout'; import type { ReactNode } from 'react'; interface Report { id: number; title: string; } interface Props { rows: Report[]; } export default function Reports({ rows }: Props) { return ( <> <Head title="Reports" /> <div className="p-6 max-w-6xl mx-auto"> <h1 className="text-2xl font-semibold">Reports</h1> <ul className="menu mt-4"> {rows.map((r) => ( <li key={r.id}>{r.title}</li> ))} </ul> </div> </> ); } Reports.layout = (page: ReactNode) => <AppLayout>{page}</AppLayout>; -
Optional: add a sidebar entry in
resources/js/layouts/AppLayout.tsx'sNAVarray.
Forms
Use Inertia's useForm with @artisanpack-ui/react/form components:
import { useForm } from '@inertiajs/react';
import { Button, Input } from '@artisanpack-ui/react/form';
const form = useForm({ title: '' });
<form onSubmit={(e) => { e.preventDefault(); form.post('/reports'); }}>
<Input
name="title"
label="Title"
value={form.data.title}
error={form.errors.title}
onChange={(e) => form.setData('title', e.target.value)}
required
/>
<Button type="submit" color="primary" loading={form.processing}>Save</Button>
</form>
Flash messages
Returning back()->with('success', '...') from a controller surfaces as a toast — HandleInertiaRequests shares flash and InertiaToastProvider (in AppLayout/AuthLayout) listens for it.
Next steps
- Authentication — controllers + Form Request flow
- Components — what's available in
@artisanpack-ui/react - Testing — Pest + Inertia assertions