aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Web Development

Laravel Blade Component and Slots: A Practical Guide

A Laravel Blade component lets you capture the repeating parts of your interface in one place and reuse them on every page. Instead of copy-pasting structures like buttons, cards, alerts or modals, you define them as components: you pass data in through props and keep the content flexible with slots. In this guide I walk through building Blade components from scratch, the difference between anonymous and class-based components, how props and slots work together, and practical tips you will actually use in real projects.

What is a Blade component and why use one?

Blade is Laravel's templating engine, and components are its reusable, self-contained pieces. A component has two parts: the tag you use from the outside (for example <x-alert />) and the Blade file behind it. The benefits are clear:

  • Less repetition: you don't rewrite the same card on ten pages.
  • Easier maintenance: when the design changes, you edit a single file.
  • Better readability: the page template is made of meaningful tags.
  • Testability: you can verify components in isolation.

Creating your first component

The fastest way to scaffold a component is with Artisan. The command below generates both a class and a view file:

php artisan make:component Alert

This creates two files: app/View/Components/Alert.php (the component class) and resources/views/components/alert.blade.php (the view). To use the component on a page, write its tag with the x- prefix:

<x-alert />

Folder structure is reflected with a separator instead of a slash. For example, the file resources/views/components/forms/input.blade.php is called as <x-forms.input />.

Passing data with props

Components usually receive data from the outside. In a class-based component you define this through constructor parameters. In the example below, type and message are props:

<?php

namespace App\View\Components;

use Illuminate\View\Component;
use Illuminate\View\View;

class Alert extends Component
{
    public function __construct(
        public string $type = 'info',
        public string $message = '',
    ) {}

    public function render(): View
    {
        return view('components.alert');
    }
}

In the view file you access these properties directly:

<div class="alert alert-{{ $type }}">
    {{ $message }}
</div>

When using it, you pass props like HTML attributes. Use a plain attribute for static values and the : prefix for variables:

<x-alert type="danger" message="Record deleted." />
<x-alert type="success" :message="$notice" />

Attribute names are automatically converted to camelCase: if you write card-title in HTML, you receive it as $cardTitle in the class.

Keeping content flexible with slots

Props are ideal for simple values, but when you want to put HTML, other components or longer text inside a component, you use a slot. Everything between the opening and closing tags lands in the {{ $slot }} variable in the view:

<!-- components/card.blade.php -->
<div class="card">
    <div class="card-body">
        {{ $slot }}
    </div>
</div>
<x-card>
    <p>This text is placed directly into the slot.</p>
</x-card>

Named slots

Most components have more than one content area: a header, a body, a footer. For this you define named slots. In the view, you mark each area with its own variable:

<!-- components/card.blade.php -->
<div class="card">
    <div class="card-header">{{ $title }}</div>
    <div class="card-body">{{ $slot }}</div>
</div>

When using it, you fill that area with <x-slot:title>; any unnamed content goes to the default $slot:

<x-card>
    <x-slot:title>
        Monthly Report
    </x-slot>

    <p>The main content goes here.</p>
</x-card>

Anonymous components and attributes

You don't have to write a class for every component. For simple, view-only structures, an anonymous component is enough: you just create a Blade file under resources/views/components/, no class required. You declare props at the top of the file:

<!-- components/badge.blade.php -->
@props(['color' => 'gray'])

<span class="badge badge-{{ $color }}">
    {{ $slot }}
</span>

Every attribute you didn't declare is collected in the $attributes bag. You can forward these to the root element, and even merge classes intelligently:

<span {{ $attributes->merge(['class' => 'badge']) }}>
    {{ $slot }}
</span>

So when you write <x-badge class="ml-2" id="role">, the existing badge class is kept and the incoming ml-2 and id are added. This approach makes components far more flexible.

Good habits in practice

  • Keep components that rarely change and have simple content anonymous; choose class-based when you need logic (fetching data, computation).
  • Give props clear, consistent names; define defaults to reduce misuse.
  • Leave room for flexibility with $attributes->merge(), but keep critical classes fixed.
  • Break up very large components; each component should do one job well.

Frequently Asked Questions

Should I use an anonymous or a class-based component?

If the content is purely a view and needs no PHP logic, an anonymous component is simpler and faster. If you need to process data, call a service or do calculations, prefer a class-based component.

What is the difference between props and slots?

Props are for passing simple values (text, numbers, booleans) from the outside and are written as attributes. A slot lets you place HTML or other components inside the component; it goes between the opening and closing tags.

Why isn't my component tag working?

The most common causes are: the file not being under resources/views/components/, a naming mismatch, or a stale view cache. Clear the cache with php artisan view:clear and compare the file path against the tag.

Want to build a clean, reusable UI layer in your project? I develop maintainable, scalable applications with Laravel and Blade. To talk through your idea, get in touch with me.

Devamı için