Together with Marcel Pociot and our colleagues at Beyond Code and Spatie, I'm currently building Flare, a paid service which will be revealed at Laracon EU. Together with the service we'll release a package that will change the way you will work with Laravel. To stay in the loop subscribe to our mailinglist at https://flareapp.io

Use custom html components in your Blade views

Original – by Freek Van der Herten – 7 minute read

Today we launched our newest package called BladeX. In short this package provides you with an easy html like way to render custom html components in your Blade views. In this blogpost I'd like to introduce the package to you.

A first example

When building a server rendered app you're probably going to wind up with various pieces of html that you want to reuse. Think of things like form components, alerts and entire layouts. There are various options to make such html reusable. You can simply create your own custom function, or use an html builder, or use Blade's @include or @component directives.

Even though IT is sometimes seen as an exact science, it seems like every programmer has his/her own personal preference on how to deal with html. In my opinion al the options mentioned above are valid. In most of our own projects at Spatie we have used a combination of them all.

In particular we like Blade's @component directive. Inspired by Vue, a Blade component is an awesome way to reuse html. Here's a quick example on how to use it. Let's create an alert component!

{{-- resources/views/components/myAlert.blade.php --}}
<div :class="$type">
   {{ $message }}
</div>

Using the @component directive you can use that component like this.

{{-- in a view --}}
@component('components/myAlert', [
   'type' => 'error',
   'message' => $message
])
@endcomponent

That directive isn't that hard to use but it is very PHP like. Wouldn't it be nice if we could use that myAlert component just like we are able in Vue with an html like syntax?

With our BladeX package installed you can use the myAlert component like this:

<my-alert type="error" :message="$message" />

Using an html like syntax you'll need less characters and (in my opinion) the template becomes more readable.

Using variables

When using a BladeX component all attributes will be passed as variables to the underlying Blade view.

{{-- the `myAlert` view will receive a variable named `type` with a value of `error` --}}
 
<my-alert type="error">

If you want to pass on a php variable or something that needs to be evaluated you must prefix the attribute name with :. We borrowed that syntax from Vue.

{{-- the `myAlert` view will receive the contents of `$message` --}}
<my-alert type="error" :message="$message">

{{-- the `myAlert` view will receive the uppercased contents of `$message` --}}
<my-alert type="error" :message="strtoupper($message)">

Using slots

BladeX support slots too. This layout component

{{-- resources/views/components/layout.blade.php --}}

<div>
    <h1>{{ $title }}</h1>
    <div class="flex">
        <div class="w-1/3">
            {{ $sidebar }}
        </div>
        <div class="w-2/3">
            {{ $slot }}
        </div>
    </div>
    <footer>
        {{ $footer }}
    </footer>
</div>

can be used in your views like this:

<layout title="Zed's chopper">
    <slot name="sidebar">
        <ul>
            <li>Home</li>
            <li>Contact</li>
        </ul>
    </slot>

    <main class="content">Whose motorcycle is this?</main>

    <slot name="footer">It's not a motorcycle honey, it's a chopper.</slot>
</layout>

Prefixing components

A few fellow devs have voiced their concern that if you're using Vue of React it might be hard to distinguish BladeX components from JavaScript components. If you share that concern, you'll be happy to learn that the package allow you to globally set a prefix for BladeX components.

Setting a global prefix is easy.

BladeX::component('my-alert', 'components.myAlert');

BladeX::prefix('x');

All your registered components can now be used like this:

<x-my-alert message="Notice the prefix!" />

How all this works under the hood

To actually use a BladeX component you first have to register it. You can do this in the AppServiceProvider or a service provider of your own.

BladeX::component('my-alert', 'components.myAlert')

In the Spatie\BladeX\BladeXServiceProvider, which is loaded automatically when the package is installed we extend Blade's default compiler with our own BladeXCompiler. The BladeXCompiler loops over all registered components. That class contains two regexes, carefully crafted by Alex and Seb, to replace BladeX component usages such as this

<my-alert type="error" :message="$message" />

to the the equivalent code using Blade's @component directives.

@component('components/myAlert', [
   'type' => 'error',
   'message' => $message
])
@endcomponent

After that, Blade will kick in and parse the html as usual. Caching views will just work, so there isn't a performance penalty for this at all. Because all this happens before any html is sent to the browser, there aren't any interop issues with client side frameworks like Vue.js.

How we made this

I'm proud of the features our package brings, but I'm equally proud of how we made this package. The problem of html generation was discussed during a lunch on Friday. In that same discussing the idea sprouted to build BladeX. At our company everybody is allowed some time to work on open source. It so happened that everybody still have some open source time left for that week.

Nearly the entire development team sat down the whole afternoon in our meeting room to build the package. Even though most packages are team work, most of them have a principal author and the rest of the team polishes the produced code. BladeX was a real team effort where all authors contributed while the package was being created. It was a really fun experience and I hope we're going to create future packages this way again.

Normally we give our packages dry, descriptive names like laravel-permission, laravel-medialibrary or laravel-backup. If we would follow that line of naming BladeX should have been called laravel-html-components or something similar. During development Alex came up with the name BladeX. It sounds so badass that we decided to stick with it.

Closing thoughts

v1.0.0 is tagged but we aren't going stop development here. In the latest North Meets South podcast Jacob and Michael discussed BladeX and shared some interesting ideas for it. We are going to investigate some integration with our laravel-view-components and/or Laravel's native view composers to easily transform and fetch data before it gets passed into the component.

If you like BladeX go take a look at all the other open source packages our team has made previously. If you like our work, consider supporting us via Patreon.

I'm planning on writing a blogpost soon on how to build common crud interface in a modern way. That post will surely feature BladeX, laravel-query-builder, laravel-view-models and a few of our other packages.

If you have any question on BladeX feel free to use the comments below or open up an issue at the repo on GitHub.

Stay up to date with all things Laravel, PHP, and JavaScript.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Uyo-obong liked on 13th August 2019
Guus liked on 13th August 2019
Kusha liked on 13th August 2019
Laurent B retweeted on 13th August 2019
Mitul Golakiya liked on 13th August 2019
Josh Bruce liked on 13th August 2019
Bobby Bouwmann liked on 13th August 2019
Ratting Gergely liked on 12th August 2019
Janos Papp liked on 12th August 2019
alaa m Ibrahim liked on 12th August 2019
Ashot Nalbandyan liked on 12th August 2019
Ashot Nalbandyan retweeted on 12th August 2019
Julius Ehrlich liked on 12th August 2019
이현석 Hyunseok Lee liked on 12th August 2019
Victor Guerrero liked on 12th August 2019
Franco Gilio liked on 12th August 2019
Drew Roberts liked on 12th August 2019
Charles Bowen liked on 12th August 2019
Marcin liked on 12th August 2019
Maulik Shah liked on 12th August 2019
Michaël De Boey liked on 12th August 2019
 Mario Mendoza  liked on 12th August 2019
David Cottila retweeted on 12th August 2019
 Mario Mendoza  retweeted on 12th August 2019
Renato VG liked on 12th August 2019
Anton Kristensen liked on 12th August 2019
Adam Wathan liked on 12th August 2019
Spatie retweeted on 12th August 2019
Marcel Pociot 🎆 retweeted on 12th August 2019
Rajesh Dewle liked on 12th August 2019
Max Pshenichnikov liked on 12th August 2019
Juan Pablo 👨🏻‍💻 liked on 11th August 2019
iBoedel replied on 11th August 2019
Thank you for sharing. Looking fwd for Amsterdam
Khurram Shahzad liked on 11th August 2019
Melbourne Laravel retweeted on 11th August 2019
Roberto B liked on 11th August 2019
David liked on 11th August 2019
Thibault Lavoisey liked on 11th August 2019
patrosmania liked on 11th August 2019
Andikan Affiah liked on 10th August 2019
Strotgen liked on 10th August 2019
arondeparon liked on 10th August 2019
Stefan liked on 10th August 2019
Carlos Cruz retweeted on 10th August 2019
Ihor Vorotnov • 25% liked on 10th August 2019
od3n liked on 10th August 2019
Cody liked on 10th August 2019
ApoNie liked on 10th August 2019
Prasad Chinwal liked on 10th August 2019
Alejandro Vásquez N. liked on 10th August 2019
Miguel Piedrafita 👨‍💻 liked on 10th August 2019
Burak Erdem liked on 10th August 2019
Pooyan R replied on 10th August 2019
I wish we could have you in our meetup in Copenhagen. :)
Pablo Román liked on 10th August 2019
Gültekin Yaman liked on 10th August 2019
Mak Man liked on 10th August 2019
Simon Payne liked on 10th August 2019
Simon Payne retweeted on 10th August 2019
Javier Quintana retweeted on 10th August 2019
Felipe Dalcin liked on 10th August 2019
Javier Quintana liked on 10th August 2019
Johnson Page liked on 10th August 2019
Gabriel liked on 10th August 2019
marco asperti liked on 10th August 2019
marco asperti retweeted on 10th August 2019
Laravel School replied on 10th August 2019
Ibm Plex mono looks amazing
Ulrich Anani liked on 10th August 2019
Laravel School retweeted on 10th August 2019
Ulrich Anani retweeted on 10th August 2019
Laravel School liked on 10th August 2019
Beta liked on 10th August 2019
Adrian Nürnberger 🐙 replied on 10th August 2019
Nice talk thanks for sharing!
Adrian Nürnberger 🐙 liked on 10th August 2019
Bilal retweeted on 10th August 2019
Wrends liked on 10th August 2019
Makabi Yelmis liked on 10th August 2019
envomer liked on 10th August 2019
Roman Pronskiy liked on 10th August 2019
Boris DEHOUMON liked on 10th August 2019
Clevon Noel 🇬🇩 liked on 10th August 2019
Jeri liked on 10th August 2019
Jeri retweeted on 10th August 2019
JuanDMeGon liked on 10th August 2019
JuanDMeGon retweeted on 10th August 2019
swapnilsarwe liked on 10th August 2019
Ahmad Ripaldi liked on 10th August 2019
Elie Andraos retweeted on 10th August 2019
Craig Potter liked on 10th August 2019
Martin Medina liked on 10th August 2019
Jordan Hall retweeted on 10th August 2019
Jordan Hall liked on 10th August 2019
Adinnu Benedict retweeted on 9th August 2019
João Patrício liked on 9th August 2019
Adinnu Benedict liked on 9th August 2019
Andrew Clinton liked on 9th August 2019
Andrew Clinton retweeted on 9th August 2019
Wyatt liked on 9th August 2019
Mubassir Hayat retweeted on 9th August 2019
zorigitano liked on 9th August 2019
Mickaël Isaert liked on 9th August 2019
DN liked on 9th August 2019
Lib liked on 9th August 2019
Herman Schutte liked on 9th August 2019
Andrei Scripcaru liked on 9th August 2019
Axel Alvarado liked on 9th August 2019
PHP Synopsis retweeted on 9th August 2019
Michael Dyrynda retweeted on 9th August 2019
Solum DeSignum liked on 9th August 2019
Gareth Redfern retweeted on 9th August 2019
Mozammil liked on 9th August 2019
Gareth Redfern liked on 9th August 2019
Vitaly Yushkevich liked on 9th August 2019
Joe Rushton liked on 9th August 2019
Maarten Buis liked on 9th August 2019
[object Object] liked on 9th August 2019
Brian replied on 9th August 2019
Nice talk! Id watch SpatieCasts: the making and maintaining of Spatie packages. Hell maybe even subscribe haha
Richard Ottinger liked on 9th August 2019
Chea Bonnak liked on 9th August 2019
Günther Debrauwer liked on 9th August 2019
Lee Overy liked on 9th August 2019
Manuel Teuber liked on 9th August 2019
ArielSalvadorDev liked on 9th August 2019
Ramiro Varandas Jr liked on 9th August 2019
ArielSalvadorDev retweeted on 9th August 2019
alan wilson retweeted on 9th August 2019
Ray Blair liked on 9th August 2019
Anne Koep retweeted on 9th August 2019
Alan Scott‽ liked on 9th August 2019
Vítor Arjol liked on 9th August 2019
Dennis Rodis liked on 9th August 2019
Luis Cortés liked on 9th August 2019
Muhammad Shafeeq liked on 9th August 2019
laravelgr retweeted on 9th August 2019
OZA 🇧🇫 liked on 9th August 2019
zaichaopan liked on 9th August 2019
Flamur Mavraj liked on 9th August 2019
Jarryd liked on 9th August 2019
Paul Rose liked on 9th August 2019
Vladyslav liked on 9th August 2019
Jino Antony liked on 9th August 2019
Jess Archer 👩‍💻 liked on 9th August 2019
ariesw liked on 9th August 2019
Patrick Brouwers liked on 9th August 2019
Ed Grosvenor liked on 9th August 2019
Tom Witkowski retweeted on 9th August 2019
Tom Witkowski liked on 9th August 2019
Gurinder Chauhan retweeted on 9th August 2019
Matt Libera liked on 9th August 2019
Stephan Köllen liked on 9th August 2019
tokobuku_jiban liked on 9th August 2019
Matt Murtaugh liked on 9th August 2019
Patrick Brouwers retweeted on 9th August 2019
Vaibhav Pardeshi liked on 9th August 2019
Osasu Aebong liked on 9th August 2019
Julio Serpone liked on 9th August 2019
eCreeth liked on 9th August 2019
austin kregel liked on 9th August 2019
Rudi van Zandwijk liked on 9th August 2019
Eddie Palmans liked on 9th August 2019
Mihai liked on 9th August 2019
Rod Elias liked on 9th August 2019
mwm [ ⚡️ , 🔑 ] liked on 9th August 2019
Ashish K. Poudel liked on 9th August 2019
Carlos Rodríguez retweeted on 9th August 2019
Mithicher Baro liked on 9th August 2019
Mithicher Baro retweeted on 9th August 2019
Osasu Aebong retweeted on 9th August 2019
docker system prune liked on 9th August 2019
oluwajubelo loves VueJS 🚨 liked on 9th August 2019
kapil retweeted on 9th August 2019
Ruslan liked on 9th August 2019
Célien Boillat 🇨🇭 liked on 9th August 2019
Levis Orgil liked on 9th August 2019
jaouad liked on 9th August 2019
NUNO MADURO 💡 liked on 9th August 2019
jaouad retweeted on 9th August 2019
Bas de Groot liked on 9th August 2019
Cameron Scott liked on 9th August 2019
Brendan Urquhart liked on 9th August 2019
Victor Hugo retweeted on 9th August 2019
Vaughany liked on 9th August 2019
Edwin I Arellano liked on 9th August 2019
Arash liked on 9th August 2019
Daniel Schmitz liked on 9th August 2019
Victor Hugo liked on 9th August 2019