#การใช้งาน MUI กับ Laravel 13 + React + Inertia

การพัฒนา Web Application ด้วย Laravel ไม่ได้จำกัดอยู่เฉพาะ Blade หรือ Tailwind CSS เท่านั้น หากต้องการสร้าง UI ที่มี Component พร้อมใช้งานจำนวนมาก เช่น Button, TextField, Dialog, Table, Snackbar หรือ Data Grid เราสามารถใช้ Material UI (MUI) ร่วมกับ React และ Inertia.js ได้อย่างมีประสิทธิภาพ

แนวทางที่เหมาะกับ Laravel 13 คือ

Laravel 13
   ↓
Inertia 3
   ↓
React 19 + TypeScript
   ↓
Material UI (MUI)

Laravel จะรับผิดชอบงานฝั่ง Backend เช่น Routing, Validation, Authentication, Authorization และ Database ส่วน React + MUI จะรับผิดชอบด้าน User Interface


#MUI คืออะไร

MUI (Material UI) เป็น React Component Library ที่พัฒนาตามแนวคิด Material Design โดยมี Component พร้อมใช้งานจำนวนมาก เช่น

  • Button
  • TextField
  • Card
  • AppBar
  • Drawer
  • Dialog
  • Snackbar
  • Alert
  • Table
  • Grid
  • Tabs
  • Data Grid

ตัวอย่าง

import Button from '@mui/material/Button';

export default function Example() {
    return (
        <Button variant="contained">
            Save
        </Button>
    );
}

เนื่องจาก MUI เป็น React Component Library จึงไม่สามารถนำ Component ของ MUI ไปใช้ใน Blade Template โดยตรงได้

ดังนั้น Stack ที่เหมาะสมคือ

Laravel + Inertia + React + MUI

#Architecture

ภาพรวม Architecture

Browser
   │
   ▼
React + MUI
   │
   ▼
Inertia.js
   │
   ▼
Laravel Route
   │
   ▼
Controller
   │
   ▼
Eloquent ORM
   │
   ▼
Database

MUI ทำหน้าที่เป็น Presentation Layer

ส่วน Laravel ทำหน้าที่เกี่ยวกับ

Routing
Validation
Authentication
Authorization
Business Logic
Database
Queue
Cache
Notification

#1. สร้าง Laravel Project

ติดตั้ง Laravel Installer

composer global require laravel/installer

จากนั้นสร้าง Project

laravel new laravel-mui

เลือก React Starter Kit

เข้า Project

cd laravel-mui

ติดตั้ง Package

npm install

รัน Development Server

composer run dev

หรือแยกรัน

php artisan serve

และ

npm run dev

#2. ติดตั้ง Material UI

ติดตั้ง MUI

npm install @mui/material @emotion/react @emotion/styled

ติดตั้ง Material Icons

npm install @mui/icons-material

หากต้องการใช้ Roboto Font

npm install @fontsource/roboto

#3. สร้าง MUI Theme

สร้างไฟล์

resources/js/theme.ts

ตัวอย่าง

import { createTheme } from '@mui/material/styles';

const theme = createTheme({
    palette: {
        primary: {
            main: '#1976d2',
        },
        secondary: {
            main: '#9c27b0',
        },
    },

    typography: {
        fontFamily: 'Roboto, sans-serif',
    },

    shape: {
        borderRadius: 10,
    },
});

export default theme;

ข้อดีของ Theme คือสามารถกำหนด Design System ของระบบจากจุดเดียว เช่น

  • Primary Color
  • Secondary Color
  • Typography
  • Border Radius
  • Component Style
  • Dark Mode

#4. ใช้ ThemeProvider

แก้ไขไฟล์

resources/js/app.tsx

เพิ่ม

import {
    CssBaseline,
    ThemeProvider
} from '@mui/material';

import theme from './theme';

ครอบ React Application

<ThemeProvider theme={theme}>
    <CssBaseline />

    {app}
</ThemeProvider>

CssBaseline จะช่วย Reset CSS และทำให้ Styling ของ MUI สอดคล้องกันทั้งระบบ


#5. ทดลองสร้างหน้า MUI

สร้างไฟล์

resources/js/pages/mui-demo.tsx
import {
    Alert,
    Box,
    Button,
    Card,
    CardContent,
    Container,
    Stack,
    Typography,
} from '@mui/material';

export default function MuiDemo() {
    return (
        <Container maxWidth="md" sx={{ py: 5 }}>
            <Stack spacing={3}>

                <Typography variant="h3">
                    Laravel + MUI
                </Typography>

                <Alert severity="success">
                    MUI ทำงานร่วมกับ Laravel ได้แล้ว
                </Alert>

                <Card>
                    <CardContent>

                        <Typography
                            variant="h5"
                            gutterBottom
                        >
                            Material UI
                        </Typography>

                        <Typography color="text.secondary">
                            หน้านี้ถูก Render ด้วย React และ MUI
                        </Typography>

                        <Box sx={{ mt: 3 }}>
                            <Button variant="contained">
                                Get Started
                            </Button>
                        </Box>

                    </CardContent>
                </Card>

            </Stack>
        </Container>
    );
}

สร้าง Route

use Illuminate\Support\Facades\Route;
use Inertia\Inertia;

Route::get('/mui-demo', function () {
    return Inertia::render('mui-demo');
});

เปิด Browser

http://localhost:8000/mui-demo

#6. ส่งข้อมูลจาก Laravel ไป React

สมมติว่ามี Product

สร้าง Model

php artisan make:model Product -mcr

Controller

namespace App\Http\Controllers;

use App\Models\Product;
use Inertia\Inertia;
use Inertia\Response;

class ProductController extends Controller
{
    public function index(): Response
    {
        return Inertia::render('products/index', [
            'products' => Product::query()
                ->latest()
                ->get([
                    'id',
                    'name',
                    'price',
                ]),
        ]);
    }
}

Route

use App\Http\Controllers\ProductController;

Route::get(
    '/products',
    [ProductController::class, 'index']
)->name('products.index');

ข้อมูลจะถูกส่งไปเป็น Props ของ React Component


#7. แสดงข้อมูลด้วย MUI Table

สร้าง

resources/js/pages/products/index.tsx
import {
    Container,
    Paper,
    Table,
    TableBody,
    TableCell,
    TableContainer,
    TableHead,
    TableRow,
    Typography,
} from '@mui/material';

interface Product {
    id: number;
    name: string;
    price: number;
}

interface Props {
    products: Product[];
}

export default function ProductIndex({
    products
}: Props) {

    return (
        <Container
            maxWidth="lg"
            sx={{ py: 4 }}
        >

            <Typography
                variant="h4"
                sx={{ mb: 3 }}
            >
                Products
            </Typography>

            <TableContainer component={Paper}>

                <Table>

                    <TableHead>
                        <TableRow>
                            <TableCell>ID</TableCell>
                            <TableCell>Name</TableCell>
                            <TableCell align="right">
                                Price
                            </TableCell>
                        </TableRow>
                    </TableHead>

                    <TableBody>

                        {products.map((product) => (

                            <TableRow key={product.id}>

                                <TableCell>
                                    {product.id}
                                </TableCell>

                                <TableCell>
                                    {product.name}
                                </TableCell>

                                <TableCell align="right">
                                    {product.price.toLocaleString()}
                                </TableCell>

                            </TableRow>

                        ))}

                    </TableBody>

                </Table>

            </TableContainer>

        </Container>
    );
}

ข้อดีคือ React ไม่จำเป็นต้องเรียก REST API เพิ่ม เพราะข้อมูลถูกส่งจาก Laravel ผ่าน Inertia


#8. สร้าง Form ด้วย MUI + Inertia

สร้างหน้า

resources/js/pages/products/create.tsx
import { useForm } from '@inertiajs/react';

import {
    Alert,
    Button,
    Container,
    Stack,
    TextField,
    Typography,
} from '@mui/material';

import type { FormEvent } from 'react';

export default function ProductCreate() {

    const form = useForm({
        name: '',
        price: '',
    });

    const submit = (
        event: FormEvent
    ) => {

        event.preventDefault();

        form.post('/products');
    };

    return (

        <Container
            maxWidth="sm"
            sx={{ py: 4 }}
        >

            <Typography
                variant="h4"
                sx={{ mb: 3 }}
            >
                Create Product
            </Typography>

            <Stack
                component="form"
                spacing={3}
                onSubmit={submit}
            >

                {form.hasErrors && (

                    <Alert severity="error">
                        กรุณาตรวจสอบข้อมูลอีกครั้ง
                    </Alert>

                )}

                <TextField
                    label="Product Name"
                    value={form.data.name}

                    onChange={(event) =>
                        form.setData(
                            'name',
                            event.target.value
                        )
                    }

                    error={
                        Boolean(
                            form.errors.name
                        )
                    }

                    helperText={
                        form.errors.name
                    }

                    fullWidth
                />

                <TextField
                    label="Price"
                    type="number"

                    value={form.data.price}

                    onChange={(event) =>
                        form.setData(
                            'price',
                            event.target.value
                        )
                    }

                    error={
                        Boolean(
                            form.errors.price
                        )
                    }

                    helperText={
                        form.errors.price
                    }

                    fullWidth
                />

                <Button
                    type="submit"
                    variant="contained"
                    disabled={form.processing}
                >
                    {form.processing
                        ? 'Saving...'
                        : 'Save'
                    }
                </Button>

            </Stack>

        </Container>
    );
}

Laravel Validation

$data = $request->validate([
    'name' => [
        'required',
        'string',
        'max:255'
    ],

    'price' => [
        'required',
        'numeric',
        'min:0'
    ],
]);

เมื่อ Validation Error เกิดขึ้น Inertia จะส่ง Error กลับมายัง React

จากนั้น MUI สามารถแสดงผลด้วย

<TextField
    error={Boolean(form.errors.name)}
    helperText={form.errors.name}
/>

#9. ใช้ MUI Icons

ติดตั้ง

npm install @mui/icons-material

ตัวอย่าง

import AddIcon from '@mui/icons-material/Add';

import Button from '@mui/material/Button';

<Button
    variant="contained"
    startIcon={<AddIcon />}
>
    Add Product
</Button>

#10. สร้าง Dashboard Layout

MUI มี Component ที่เหมาะสำหรับ Dashboard เช่น

AppBar
Drawer
Toolbar
Grid
Card
List
Table
Data Grid

ตัวอย่าง

import {
    Card,
    CardContent,
    Grid,
    Typography,
} from '@mui/material';

export default function Dashboard() {

    return (

        <Grid
            container
            spacing={3}
        >

            <Grid size={{
                xs: 12,
                md: 4
            }}>

                <Card>

                    <CardContent>

                        <Typography
                            color="text.secondary"
                        >
                            Users
                        </Typography>

                        <Typography variant="h4">
                            1,250
                        </Typography>

                    </CardContent>

                </Card>

            </Grid>

            <Grid size={{
                xs: 12,
                md: 4
            }}>

                <Card>

                    <CardContent>

                        <Typography
                            color="text.secondary"
                        >
                            Orders
                        </Typography>

                        <Typography variant="h4">
                            380
                        </Typography>

                    </CardContent>

                </Card>

            </Grid>

            <Grid size={{
                xs: 12,
                md: 4
            }}>

                <Card>

                    <CardContent>

                        <Typography
                            color="text.secondary"
                        >
                            Revenue
                        </Typography>

                        <Typography variant="h4">
                            ฿245,000
                        </Typography>

                    </CardContent>

                </Card>

            </Grid>

        </Grid>
    );
}

#11. ใช้ MUI Dialog

ตัวอย่าง Confirmation Dialog

import {
    Button,
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
} from '@mui/material';

import { useState } from 'react';

export default function DeleteDialog() {

    const [open, setOpen] = useState(false);

    return (

        <>

            <Button
                color="error"
                onClick={() =>
                    setOpen(true)
                }
            >
                Delete
            </Button>

            <Dialog
                open={open}
                onClose={() =>
                    setOpen(false)
                }
            >

                <DialogTitle>
                    Delete Product
                </DialogTitle>

                <DialogContent>
                    Are you sure you want to delete this product?
                </DialogContent>

                <DialogActions>

                    <Button
                        onClick={() =>
                            setOpen(false)
                        }
                    >
                        Cancel
                    </Button>

                    <Button
                        color="error"
                        variant="contained"
                    >
                        Delete
                    </Button>

                </DialogActions>

            </Dialog>

        </>

    );
}

#12. ใช้ Snackbar

Snackbar เหมาะสำหรับแสดง Notification

import {
    Alert,
    Snackbar,
} from '@mui/material';

import { useState } from 'react';

export default function Notification() {

    const [open, setOpen] = useState(true);

    return (

        <Snackbar
            open={open}
            autoHideDuration={3000}
            onClose={() =>
                setOpen(false)
            }
        >

            <Alert
                severity="success"
                variant="filled"
            >
                บันทึกข้อมูลเรียบร้อย
            </Alert>

        </Snackbar>

    );
}

สามารถนำ Laravel Flash Session มาเชื่อมกับ Snackbar ได้


#13. ใช้ MUI Data Grid

สำหรับระบบที่มีข้อมูลจำนวนมากสามารถใช้ MUI X Data Grid

ติดตั้ง

npm install @mui/x-data-grid

ตัวอย่าง

import {
    DataGrid
} from '@mui/x-data-grid';

const columns = [

    {
        field: 'id',
        headerName: 'ID',
        width: 90,
    },

    {
        field: 'name',
        headerName: 'Name',
        flex: 1,
    },

    {
        field: 'price',
        headerName: 'Price',
        width: 150,
    },

];

export default function ProductTable({
    products
}) {

    return (

        <DataGrid
            rows={products}
            columns={columns}

            initialState={{
                pagination: {
                    paginationModel: {
                        pageSize: 10,
                    },
                },
            }}

            pageSizeOptions={[
                10,
                25,
                50
            ]}
        />

    );
}

เหมาะกับ

  • Admin Panel
  • Inventory
  • Report
  • User Management
  • Audit Log

#14. Laravel Pagination + MUI

หากข้อมูลมีจำนวนมากไม่ควรโหลดทั้งหมดจาก Database

ใช้ Laravel Pagination

return Inertia::render(
    'products/index',
    [
        'products' =>
            Product::query()
                ->latest()
                ->paginate(10),
    ]
);

ข้อมูลที่ได้จะมีโครงสร้างประมาณ

products.data
products.current_page
products.last_page
products.total

จากนั้นสามารถนำไปใช้กับ

MUI Pagination
MUI TablePagination
MUI Data Grid

#15. Dark Mode

MUI รองรับ Dark Mode

import {
    createTheme
} from '@mui/material/styles';

export function createAppTheme(
    mode: 'light' | 'dark'
) {

    return createTheme({

        palette: {
            mode,

            primary: {
                main: '#1976d2',
            },
        },

    });
}

จากนั้นควบคุม Mode ด้วย React State

Light
Dark
System

#16. MUI กับ Tailwind ใช้พร้อมกันได้หรือไม่

สามารถใช้ร่วมกันได้

ตัวอย่าง

<Box className="p-4">

    <Button variant="contained">
        Save
    </Button>

</Box>

แต่ควรกำหนดแนวทางให้ชัดเจน เช่น

MUI Theme
    ↓
Design Token

MUI sx
    ↓
Component Styling

Tailwind
    ↓
Utility / Layout บางส่วน

ไม่ควรกำหนด Style เดียวกันซ้ำทั้ง

sx
className
CSS

เพราะจะทำให้ Maintenance ยากขึ้น


#17. MUI กับ shadcn/ui

Laravel React Starter Kit อาจมี shadcn/ui อยู่แล้ว

เราสามารถติดตั้ง MUI เพิ่มได้

แนวทางที่แนะนำ

Laravel React Starter Kit

        ↓

ติดตั้ง MUI

        ↓

ใช้ MUI กับหน้าใหม่

        ↓

ค่อย ๆ เปลี่ยน Component

        ↓

ลด Component ที่ไม่จำเป็น

ไม่จำเป็นต้องลบ shadcn/ui และ Tailwind ออกทันที


#18. โครงสร้าง Project ที่แนะนำ

laravel-mui
│
├── app
│   ├── Http
│   │   └── Controllers
│   │       └── ProductController.php
│   │
│   └── Models
│       └── Product.php
│
├── resources
│   ├── js
│   │
│   ├── components
│   │   ├── Navbar.tsx
│   │   ├── ConfirmDialog.tsx
│   │   └── ProductForm.tsx
│   │
│   ├── layouts
│   │   └── MuiLayout.tsx
│   │
│   ├── pages
│   │   ├── dashboard.tsx
│   │   └── products
│   │       ├── index.tsx
│   │       ├── create.tsx
│   │       └── edit.tsx
│   │
│   ├── app.tsx
│   └── theme.ts
│
└── routes
    └── web.php

#19. Best Practices

#ใช้ Laravel จัดการ Business Logic

Business Logic ควรอยู่ใน

Controller
Service
Action
Model
Policy
Form Request

ไม่ควรนำ Logic สำคัญไปไว้ใน React Component


#ใช้ Laravel Validation

ตัวอย่าง

$request->validate([
    'name' => ['required'],
]);

จากนั้นแสดง Error ด้วย MUI

<TextField
    error={
        Boolean(errors.name)
    }

    helperText={
        errors.name
    }
/>

#สร้าง Reusable Components

ตัวอย่าง

components
├── ConfirmDialog.tsx
├── DataTable.tsx
├── FormTextField.tsx
├── LoadingButton.tsx
└── PageHeader.tsx

#ใช้ Theme แทน Hard-code สี

ไม่ควร

sx={{
    backgroundColor: '#1976d2'
}}

ควรใช้

sx={{
    backgroundColor: 'primary.main'
}}

#ใช้ Server-side Pagination

สำหรับข้อมูลจำนวนมาก

Database
   ↓
Laravel paginate()
   ↓
Inertia Props
   ↓
React
   ↓
MUI Pagination

#20. Production Build

Build Frontend

npm run build

จากนั้น Deploy Laravel ตามปกติ

ตัวอย่าง Production Architecture

Internet
   ↓
Nginx
   ↓
PHP-FPM
   ↓
Laravel
   ↓
Database

Frontend Asset จะถูก Build ด้วย Vite


#Laravel + MUI เหมาะกับระบบแบบใด

MUI เหมาะกับ Laravel Application ประเภท

  • Admin Dashboard
  • ERP
  • CRM
  • Inventory
  • Back-office
  • Student Information System
  • Management System
  • Report System
  • Data Dashboard

โดยเฉพาะระบบที่มี

Form
Table
Dialog
Dashboard
Data Grid
Search
Pagination
Navigation

#สรุป

การใช้ MUI กับ Laravel เป็นแนวทางที่เหมาะสำหรับการสร้าง Web Application สมัยใหม่ที่ต้องการความสามารถของ Laravel ในฝั่ง Backend และต้องการ Component UI ที่พร้อมใช้งานจาก React Ecosystem

Stack ที่แนะนำคือ

Laravel 13
+
Inertia 3
+
React 19
+
TypeScript
+
Material UI
+
Vite

Data Flow

Route

↓

Controller

↓

Inertia::render()

↓

React Page

↓

MUI Components

↓

User Interface

Laravel ทำหน้าที่จัดการ

Business Logic
Validation
Authentication
Authorization
Database

ส่วน MUI ทำหน้าที่

Presentation Layer
Component
Layout
Form
Table
Dialog
Dashboard

เมื่อแยกหน้าที่ระหว่าง Backend และ Frontend อย่างชัดเจน จะช่วยให้ระบบสามารถพัฒนา ดูแล และขยายต่อได้ง่ายขึ้น


#คำสั่งที่ใช้บ่อย

สร้าง Laravel Project

laravel new laravel-mui

ติดตั้ง Dependency

npm install

ติดตั้ง MUI

npm install @mui/material @emotion/react @emotion/styled

ติดตั้ง Material Icons

npm install @mui/icons-material

ติดตั้ง Roboto Font

npm install @fontsource/roboto

รัน Development

composer run dev

Build Production

npm run build

#เอกสารอ้างอิง