Pendahuluan
Di artikel sebelumnya tentang Routing dan Controller, kita sudah bisa membuat Controller yang memproses request. Tapi hasil outputnya masih teks biasa. Sekarang saatnya membuat tampilan yang nyata dan dinamis!
Blade adalah template engine bawaan Laravel yang menggabungkan kekuatan PHP dengan sintaks yang jauh lebih bersih. Bayangkan HTML yang bisa menampilkan variabel, punya kondisi if, loop foreach, dan bisa diwariskan seperti class OOP.
Di akhir artikel ini, kamu akan bisa:
- Menampilkan data dari Controller ke View
- Menggunakan direktif Blade:
@if,@foreach,@for - Membuat layout yang bisa digunakan ulang
- Membuat Blade Component yang reusable
- Memahami perbedaan
{{ }}dan{!! !!}
Cara Kerja Blade
File Blade disimpan di folder resources/views/ dengan ekstensi .blade.php. Ketika diakses, Blade dikompilasi menjadi PHP murni dan di-cache, sehingga tidak ada overhead performa.
Membuat View Pertama
# Buat file view secara manual
# resources/views/tasks/index.blade.php
// Di Controller, kirim data ke view menggunakan compact() atau array
class TaskController extends Controller
{
public function index()
{
$tasks = [
['id' => 1, 'title' => 'Belajar Laravel', 'done' => false],
['id' => 2, 'title' => 'Membuat CRUD App', 'done' => true],
];
// Cara 1: compact() — nama variabel menjadi key
return view('tasks.index', compact('tasks'));
// Cara 2: array eksplisit
return view('tasks.index', ['tasks' => $tasks]);
// Cara 3: with()
return view('tasks.index')->with('tasks', $tasks);
}
}
{{-- resources/views/tasks/index.blade.php --}}
<!DOCTYPE html>
<html lang="id">
<head>
<title>Daftar Task</title>
</head>
<body>
<h1>Task Manager</h1>
<ul>
@foreach ($tasks as $task)
<li>{{ $task['title'] }}</li>
@endforeach
</ul>
</body>
</html>
Menampilkan Data: {{ }} vs {!! !!}
Ini adalah perbedaan yang sangat penting untuk keamanan:
{{-- {{ }} — AMAN: melakukan HTML escaping (mencegah XSS) --}}
{{ $user->name }}
{{-- Jika $user->name = '<script>alert("hack")</script>'
Maka output: <script>alert("hack")</script> (aman) --}}
{{-- {!! !!} — TIDAK AMAN: menampilkan HTML mentah --}}
{!! $post->html_content !!}
{{-- Gunakan HANYA jika kamu yakin kontennya aman (HTML dari editor WYSIWYG) --}}
Aturan emas: Selalu gunakan
{{ }}untuk data dari pengguna. Gunakan{!! !!}hanya untuk konten HTML yang kamu kontrol sendiri.
Menampilkan Data dengan Default
{{-- Jika $title null, tampilkan "Tanpa Judul" --}}
{{ $title ?? 'Tanpa Judul' }}
{{-- Menggunakan helper @isset --}}
@isset($user)
<p>Halo, {{ $user->name }}</p>
@endisset
Direktif Kontrol Alur
@if, @elseif, @else
@if ($user->isAdmin())
<span class="badge">Admin</span>
@elseif ($user->isPremium())
<span class="badge">Premium</span>
@else
<span class="badge">Regular</span>
@endif
{{-- Versi pendek untuk kondisi negatif --}}
@unless ($user->isLoggedIn())
<a href="/login">Login</a>
@endunless
@foreach dan @forelse
{{-- Perulangan biasa --}}
@foreach ($tasks as $task)
<div class="task">
<h3>{{ $task->title }}</h3>
<p>{{ $task->description }}</p>
</div>
@endforeach
{{-- @forelse: otomatis handle kondisi kosong --}}
@forelse ($tasks as $task)
<div class="task">{{ $task->title }}</div>
@empty
<p>Belum ada task. <a href="{{ route('tasks.create') }}">Buat task pertama!</a></p>
@endforelse
Loop Variable $loop
Blade menyediakan variabel $loop di dalam @foreach yang sangat berguna:
@foreach ($tasks as $task)
<tr class="{{ $loop->even ? 'bg-gray-100' : '' }}">
<td>{{ $loop->iteration }}</td> {{-- Nomor urut (1, 2, 3...) --}}
<td>{{ $task->title }}</td>
@if ($loop->first)
<td>⭐ Pertama</td>
@elseif ($loop->last)
<td>🏁 Terakhir</td>
@else
<td>-</td>
@endif
</tr>
@endforeach
@for dan @while
@for ($i = 1; $i <= 5; $i++)
<span>{{ $i }}</span>
@endfor
@while ($condition)
{{-- Jarang digunakan, hati-hati infinite loop --}}
@endwhile
@switch
@switch($task->priority)
@case('high')
<span style="color: red">Tinggi</span>
@break
@case('medium')
<span style="color: orange">Sedang</span>
@break
@default
<span style="color: green">Rendah</span>
@endswitch
Layout dengan Template Inheritance
Salah satu fitur terkuat Blade adalah template inheritance — kamu bisa membuat satu layout dasar yang digunakan oleh semua halaman.
Langkah 1: Buat Layout Utama
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'Task Manager')</title>
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
</head>
<body>
{{-- Navigasi --}}
<nav>
<a href="{{ route('tasks.index') }}">Task Manager</a>
@auth
<span>Halo, {{ auth()->user()->name }}!</span>
<form action="/logout" method="POST" style="display:inline">
@csrf
<button>Logout</button>
</form>
@else
<a href="/login">Login</a>
@endauth
</nav>
{{-- Flash Message --}}
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
{{-- Konten halaman (didefinisikan di child view) --}}
<main>
@yield('content')
</main>
{{-- Sidebar opsional --}}
@section('sidebar')
<aside>Default Sidebar</aside>
@show
<footer>
<p>© 2026 Task Manager</p>
</footer>
@yield('scripts')
</body>
</html>
Langkah 2: Gunakan Layout di Child View
{{-- resources/views/tasks/index.blade.php --}}
{{-- 1. Extends layout utama --}}
@extends('layouts.app')
{{-- 2. Isi section 'title' --}}
@section('title', 'Daftar Task')
{{-- 3. Isi section 'content' --}}
@section('content')
<h1>Daftar Semua Task</h1>
<a href="{{ route('tasks.create') }}">+ Tambah Task</a>
@forelse ($tasks as $task)
<div class="card">
<h3>{{ $task->title }}</h3>
<p>{{ $task->description }}</p>
<a href="{{ route('tasks.show', $task->id) }}">Lihat Detail</a>
</div>
@empty
<p>Belum ada task.</p>
@endforelse
@endsection
{{-- 4. Override section sidebar (opsional) --}}
@section('sidebar')
<aside>
<h4>Filter</h4>
<a href="?status=pending">Pending</a>
<a href="?status=done">Selesai</a>
</aside>
@endsection
{{-- 5. Tambah JavaScript khusus halaman ini --}}
@section('scripts')
<script>
console.log('Task index page loaded');
</script>
@endsection
Blade Components
Blade Components adalah cara modern (sejak Laravel 7) untuk membuat komponen UI yang reusable — mirip dengan komponen React atau Vue.
Membuat Component
# Buat component menggunakan Artisan
php artisan make:component Alert
# Membuat: app/View/Components/Alert.php
# Membuat: resources/views/components/alert.blade.php
// app/View/Components/Alert.php
class Alert extends Component
{
public function __construct(
public string $type = 'info', // 'success', 'warning', 'error', 'info'
public string $message = '',
) {}
public function render()
{
return view('components.alert');
}
}
{{-- resources/views/components/alert.blade.php --}}
<div class="alert alert-{{ $type }}">
{{ $message }}
{{-- $slot untuk konten tambahan --}}
{{ $slot }}
</div>
Menggunakan Component
{{-- Cara 1: Dengan props --}}
<x-alert type="success" message="Task berhasil disimpan!" />
{{-- Cara 2: Dengan slot (untuk konten lebih kompleks) --}}
<x-alert type="warning">
Data akan <strong>dihapus permanen</strong>. Yakin?
</x-alert>
{{-- Component tombol yang reusable --}}
<x-button variant="primary" href="{{ route('tasks.create') }}">
+ Tambah Task
</x-button>
@include — Menyertakan Sub-View
Untuk bagian halaman yang sering diulang:
{{-- resources/views/partials/task-card.blade.php --}}
<div class="card">
<h3>{{ $task->title }}</h3>
<p>{{ Str::limit($task->description, 100) }}</p>
<span class="badge {{ $task->done ? 'done' : 'pending' }}">
{{ $task->done ? 'Selesai' : 'Pending' }}
</span>
</div>
{{-- Gunakan di halaman lain --}}
@foreach ($tasks as $task)
@include('partials.task-card', ['task' => $task])
@endforeach
{{-- @include dengan kondisi --}}
@includeWhen($user->isAdmin(), 'partials.admin-controls')
@includeUnless($user->isBanned(), 'partials.comment-form')
Helper URL dan Asset
{{-- URL ke halaman --}}
<a href="{{ url('/tasks') }}">Tasks</a>
<a href="{{ route('tasks.index') }}">Tasks (named route)</a>
{{-- URL ke file di folder public/ --}}
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
<img src="{{ asset('images/logo.png') }}" alt="Logo">
<script src="{{ asset('js/app.js') }}"></script>
{{-- URL ke file upload (dari storage/) --}}
<img src="{{ Storage::url($user->avatar) }}" alt="Avatar">
Stacks — Inject Script dari Child View
{{-- Di layout utama, definisikan stack --}}
@stack('scripts')
{{-- Di child view, push script ke stack --}}
@push('scripts')
<script src="{{ asset('js/task-form.js') }}"></script>
@endpush
Contoh Praktis: Halaman Lengkap Task Manager
Berikut contoh tampilan lengkap yang mengintegrasikan semua yang sudah kita pelajari:
{{-- resources/views/tasks/index.blade.php --}}
@extends('layouts.app')
@section('title', 'Daftar Task - Task Manager')
@section('content')
<div class="container">
<div class="header">
<h1>📋 Semua Task</h1>
<a href="{{ route('tasks.create') }}" class="btn btn-primary">
+ Tambah Task
</a>
</div>
@if (session('success'))
<x-alert type="success" :message="session('success')" />
@endif
<div class="task-grid">
@forelse ($tasks as $task)
<div class="task-card {{ $task->done ? 'done' : '' }}">
<div class="task-number">{{ $loop->iteration }}</div>
<h3>{{ $task->title }}</h3>
<p>{{ Str::limit($task->description, 80) }}</p>
@if ($task->due_date)
<small>📅 {{ $task->due_date->format('d M Y') }}</small>
@endif
<div class="task-actions">
<a href="{{ route('tasks.show', $task) }}">Lihat</a>
<a href="{{ route('tasks.edit', $task) }}">Edit</a>
<form action="{{ route('tasks.destroy', $task) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" onclick="return confirm('Yakin hapus?')">
Hapus
</button>
</form>
</div>
</div>
@empty
<div class="empty-state">
<p>🎉 Tidak ada task! <a href="{{ route('tasks.create') }}">Buat yang pertama</a></p>
</div>
@endforelse
</div>
{{-- Pagination --}}
{{ $tasks->links() }}
</div>
@endsection
Troubleshooting: Error yang Sering Muncul
Undefined variable $tasks
Penyebab: Controller mengirim nama variabel yang berbeda, atau lupa mengirim data ke view.
Solusi:
// Di Controller, pastikan nama variabel sama dengan yang digunakan di Blade
return view('tasks.index', compact('tasks')); // ✅ $tasks tersedia di view
// Jangan lupa kirim data!
return view('tasks.index'); // ❌ $tasks tidak tersedia
@yield Tidak Menampilkan Konten
Penyebab: Lupa menambahkan @extends di child view, atau nama section tidak cocok.
Solusi:
{{-- Pastikan ada @extends di BARIS PERTAMA child view --}}
@extends('layouts.app') {{-- ✅ Harus ada! --}}
{{-- Pastikan nama @section sama dengan @yield di layout --}}
{{-- Di layout: @yield('content') --}}
@section('content') {{-- ✅ Nama harus sama persis --}}
Konten di sini
@endsection
Pertanyaan yang Sering Diajukan
Apa bedanya Blade vs React/Vue untuk frontend?
Blade berjalan di server-side (PHP di server menghasilkan HTML lengkap yang dikirim ke browser). React/Vue berjalan di client-side (JavaScript di browser yang merender UI). Blade lebih sederhana dan cocok untuk web app tradisional. React/Vue cocok untuk aplikasi SPA yang sangat interaktif. Banyak developer Indonesia menggunakan keduanya: Laravel sebagai API backend + React/Vue sebagai frontend. Baca lebih lanjut tentang cara mengintegrasikan keduanya (termasuk CORS).
Kapan menggunakan @include vs Blade Component?
Gunakan @include untuk partial view sederhana yang tidak butuh logic (footer, header, dsb). Gunakan Blade Component untuk elemen UI yang reusable dan punya logic sendiri (tombol, kartu, modal, alert). Component lebih OOP dan testable.
Bagaimana cara debug variabel di Blade?
{{-- Dump dan die — tampilkan isi variabel lalu hentikan eksekusi --}}
{{ dd($task) }}
{{-- Dump tanpa hentikan eksekusi --}}
{{ dump($tasks) }}
{{-- Tampilkan semua variabel yang tersedia di view ini --}}
{{ dd(get_defined_vars()) }}
Kesimpulan
Blade adalah template engine yang akan kamu gunakan di setiap proyek Laravel. Kita sudah mempelajari:
- Menampilkan data dengan
{{ }}yang aman dari XSS - Direktif kontrol alur:
@if,@foreach,@forelse,@switch - Template inheritance:
@extends,@yield,@sectionuntuk layout reusable - Blade Components:
<x-component>untuk UI yang modular @includeuntuk partial view
Di artikel berikutnya, kita masuk ke topik yang paling ditunggu: Eloquent ORM — cara Laravel berbicara dengan database menggunakan PHP yang ekspresif tanpa SQL manual.
Blade sudah kamu kuasai — tampilan aplikasimu sekarang bisa jauh lebih hidup! ✨