Frontend structure conventions for Laravel Inertia React applications based on Spatie's production practices. Use when creating, scaffolding, or reviewing frontend code in a Laravel Inertia React project. Triggers on creating React components, pages, modules, organizing frontend directories, setting up Inertia pages, structuring a React frontend within Laravel, or when the user asks about frontend file organization in an Inertia app.
96
Quality
95%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
Based on Spatie's conventions for structuring production Laravel Inertia React applications.
Four base directories under resources/js:
resources/js/
├── common/ # Generic, reusable code portable across projects
├── modules/ # Project-specific code shared across multiple pages
├── pages/ # Inertia page components
└── shadcn/ # Auto-generated shadcn/ui components (if used)common vs modules: ask "Does it relate to a domain or feature?" If yes → modules. If it's generic and project-agnostic → common.
PascalCase (e.g. Button.tsx, AuthContext.tsx)camelCase (e.g. useAuth.ts, formatDate.ts)kebab-case (e.g. date-picker/, user-management/)Small modules have a few top-level files. Larger modules organize by type:
modules/agenda/
├── components/
├── contexts/
├── constants/
├── helpers/
├── hooks/
├── stores/
└── types.ts # or types/ directory if largeThe common/ directory follows the same structure.
Pages mirror the URL structure. Components are suffixed with Page.
pages/
├── layouts/ # Global layouts
├── admin/
│ ├── layouts/ # Section-specific layouts
│ ├── users/
│ │ ├── components/ # Page-specific partials
│ │ ├── helpers/
│ │ ├── IndexPage.tsx
│ │ └── EditPage.tsx
│ └── DashboardPage.tsx
└── auth/
├── LoginPage.tsx
└── RegisterPage.tsxUse function declarations (not const arrow functions) and named exports exclusively:
// Correct
export function Button({ variant, className }: ButtonProps) {
return <button className={cn(variant, className)}>Click</button>;
}
// Wrong: const + default export
const Button = ({ variant }) => { ... };
export default Button;One component per file. No barrel files (index.ts re-exports).
Two blocks separated by a blank line: library imports first, then application imports. Use absolute paths with aliases (@/):
import { useState } from "react";
import { cn } from "@/common/helpers/cn";
import { useAgenda } from "@/modules/agenda/hooks/useAgenda";
import { AgendaItem } from "@/modules/agenda/components/AgendaItem";Sort alphabetically, with className and children last:
interface DialogProps {
onClose: () => void;
open: boolean;
title: string;
className?: string;
children: React.ReactNode;
}Use Tailwind. Single app.css for most projects. Larger projects split into:
resources/css/
├── base/
├── components/
└── utilities/For apps with distinct sections (e.g. admin/client), introduce apps/:
resources/js/
├── common/ # Shared across all zones
├── modules/ # Global modules shared across zones
├── apps/
│ ├── admin/
│ │ ├── modules/ # Admin-specific modules
│ │ ├── pages/
│ │ └── app.tsx
│ └── client/
│ ├── modules/ # Client-specific modules
│ ├── pages/
│ └── app.tsx
└── shadcn/Abstract shadcn components into simpler, project-specific implementations rather than using the low-level API directly in application code. Place abstractions in common/ or modules/ as appropriate.
355d067
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.