Hướng dẫn sử dụng cú pháp `<x-...>` trong Laravel Blade

Cú pháp `<x-...>` (Component Tag) là cách gọi và hiển thị các Blade Component theo phong cách thẻ HTML trong Laravel. Thay vì dùng `@include` hay `@extends`, bạn có thể viết giao diện dạng module trực quan, sạch sẽ và dễ tái sử dụng hơn.

Nguyễn Dương Thế Vĩ 04/10/2026 · 24 Views

1. Quy tắc Laravel tìm file component (File Mapping)

Mọi thẻ bắt đầu bằng <x-...> mặc định sẽ tìm file trong thư mục resources/views/components/:

Thẻ component Đường dẫn file tương ứng
<x-button /> resources/views/components/button.blade.php
<x-post-card /> resources/views/components/post-card.blade.php (tự khớp kebab-case)
<x-form.input /> resources/views/components/form/input.blade.php (dấu chấm = thư mục con)
<x-admin.table.row /> resources/views/components/admin/table/row.blade.php

Lưu ý: Dấu hai chấm : cũng tương đương dấu chấm: <x-form:input /> giống <x-form.input />.


2. Truyền dữ liệu: Chuỗi tĩnh vs Biến PHP

Đây là quy tắc quan trọng nhất khi dùng cú pháp <x-...>:

  • Không có dấu : ➔ Giá trị là chuỗi chữ thô (String).
  • Có dấu : phía trước ➔ Giá trị là biến PHP, biểu thức logic, số hoặc mảng.
{{-- 1. Chuỗi tĩnh --}}
<x-alert type="success" message="Đã lưu thành công" />

{{-- 2. Biến PHP (bắt buộc có dấu :) --}}
<x-user-card :user="$user" :posts-count="$count" />

{{-- 3. Biểu thức logic / Boolean / Mảng --}}
<x-modal :is-open="false" :tags="['laravel', 'blade']" />

3. Khai báo Props và Hứng Attributes tự do

Khi viết một component (ví dụ resources/views/components/form/input.blade.php):

{{-- 1. @props: Khai báo các biến component chủ động nhận & giá trị mặc định --}}
@props([
    'name',
    'label',
    'type' => 'text',
])

<div class="mb-4">
    <label class="block font-medium">{{ $label }}</label>

    {{-- 2. $attributes: Tự động hứng mọi thuộc tính HTML còn lại (id, placeholder, disabled, class...) --}}
    <input 
        type="{{ $type }}" 
        name="{{ $name }}"
        {{ $attributes->merge(['class' => 'w-full rounded border px-3 py-2']) }}
    />
</div>

Khi sử dụng:

<x-form.input 
    name="email" 
    label="Địa chỉ Email" 
    placeholder="nhap@email.com" 
    class="bg-gray-50" 
    required 
/>

👉 placeholder, required và class bg-gray-50 sẽ tự động được $attributes->merge() gắn thẳng vào thẻ <input> mà bạn không cần khai báo thêm.


4. Truyền nội dung qua Slots

Slot cho phép bạn bọc nội dung HTML bên trong thẻ component.

4.1. Slot mặc định ($slot)

Nội dung đặt giữa thẻ mở và thẻ đóng sẽ tự động rơi vào biến {{ $slot }}:

{{-- components/card.blade.php --}}
<div class="rounded-lg border p-4 shadow">
    {{ $slot }}
</div>

{{-- Cách dùng --}}
<x-card>
    <h3 class="font-bold">Tiêu đề</h3>
    <p>Nội dung chi tiết nằm ở đây...</p>
</x-card>

4.2. Named Slots (Slot có tên: <x-slot:...>)

Dùng khi component có nhiều khu vực hiển thị (Header, Body, Footer):

{{-- components/modal.blade.php --}}
<div class="modal">
    <div class="modal-header">{{ $header }}</div>
    <div class="modal-body">{{ $slot }}</div>
    <div class="modal-footer">{{ $footer }}</div>
</div>

{{-- Cách dùng --}}
<x-modal>
    <x-slot:header>
        <h2 class="text-lg">Xác nhận xóa</h2>
    </x-slot:header>

    <p>Bạn có chắc muốn xóa bản ghi này?</p>

    <x-slot:footer>
        <button>Hủy</button>
        <button>Đồng ý</button>
    </x-slot:footer>
</x-modal>

5. Dùng làm Layout với <x-layout>

Thay vì cấu trúc @extends + @section kinh điển:

File Layout: resources/views/components/layout.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>{{ $title ?? 'Website' }}</title>
</head>
<body>
    <main>{{ $slot }}</main>
    {{ $scripts ?? '' }}
</body>
</html>

Trang con: resources/views/home.blade.php

<x-layout title="Trang chủ">
    <h1>Xin chào các bạn!</h1>

    <x-slot:scripts>
        <script>console.log('Script riêng của trang home');</script>
    </x-slot:scripts>
</x-layout>

6. Bảng tra cứu nhanh cú pháp

Mục đích Cú pháp
Gọi component thư mục gốc <x-tên-file />
Gọi component trong thư mục con <x-thư-mục.tên-file />
Truyền chuỗi tĩnh title="Xin chào"
Truyền biến PHP / biểu thức :user="$user", :is-active="true"
Khai báo biến nhận & default @props(['variant' => 'primary'])
Gộp class & nhận attribute HTML {{ $attributes->merge(['class' => '...']) }}
Nội dung chính giữa 2 thẻ {{ $slot }}
Nội dung theo vùng chỉ định <x-slot:tên-vùng>...</x-slot:tên-vùng>