Laravel Blade Components

Published in Laravel on Jun 3, 2021

Here is my opinion on Blade: It is the most powerful and easy to use templating engine on the planet. At least in the PHP universe, but I haven't seen anything better anywhere else I looked (Python/Java).

The Laravel community usually agrees on the way you should use Laravel features and that's usually: Stick with the defaults. In the case of Blade it's what you get when you use any of the starter kits (Breeze or Jetstream with Livewire). Both of them make heavy use of Blade components. The Blade documentation also reflects the change away from using Blade template inheritance to fully building layouts with components only.

When I saw Tomas comment on Twitter, I figured there are still some misconceptions on what is what.

What regular Blade includes (partials) can do

Blades @include directive basically allows you to include any blade file within another blade file, optionally passing data or variables into the partial.

@include('partials.nav',[
  'current_site' => request()->route()->getPath(),
  'data' => 'some data',
])

The @include documentation has some more examples and a big note that tells you components are better.

What components bring to the table

Components were introduced with Laravel 6 but still had an awkward usage experience that forced you to write lots of boilerplate. With Laravel 7 the syntax was changed to an HTML-tag style syntax which developers are already used to from frontend frameworks like VueJS or React.

There are two main ways you can use components: As a Blade view with corresponding PHP class and as a Blade view only (anonymous component). The third way is an inline-component where you only have the PHP class and output the view using a render() method. You can think of the PHP classes as little controllers only for the component (to fetch data or do other things).

The main difference between components and includes is the ability to have slots (and of course the PHP classes). For example, lets say we want to create a button component. We would create a file button.blade.php in resources/views/components

@props([
    'type' => 'submit'
])

<button {{ $attributes->merge(['class' => 'inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500']) }}
    type="{{ $type }}"
>
    {{ $slot }}
</button>

In our Blade templates we can just use it like this:

<x-button>Press Here</x-button>

This will render a beautiful blue submit button. If we need it to be a regular button, we can just add the type. If we need to add CSS classes, we can just add them and they will be merged with the existing classes.

<x-button type="button" class="mt-5" disabled>More Margin</x-button>

You can add any attributes you want and the $attributes variable will render them. If you want to require attributes (or set defaults) you must set them as props, like above.

You can also have multiple slots like this:

<x-modal>
    <x-slot name="header">The TITLE</x-slot>
    Content of a modal
    <x-slot name="footer">
        <x-secondary-button>Cancel</x-button>
        <x-button>Submit</x-button>
    </x-slot>    
</x-modal>

The named slots will be available as $header and $footer in your template.

The main selling point of components

So beautiful thing about this, is that it keeps your main templates clean so you can quickly see what's going on. It also hides all those Tailwind classes and helps prevent redundancies. Whenever I need something twice, I extract it to a Blade component.

Soon you will have nice re-usable component libraries that you can extract to a package and use in all of your apps.

You can also add a lot of magic to your components and even go as far as having a whole datatable hidden in a Blade component.

<x-datatable :model="$products" search sortable take="10" pagination/>

This will render the full table of the given model with a search field, sortable columns and pagination (powered by Livewire).

This is an elegance you cannot achieve with regular Blade includes.