★ Use custom html components in your Blade views
Tags: laravel, php
Published: 2020-01-02 23:04:45

---
title: ★ Use custom html components in your Blade views
published: true
date: 2018-10-01 09:00:00 UTC
tags: laravel, php
canonical_url: https://freek.dev/1169-use-custom-html-components-in-your-blade-views
---

Today we launched [our newest package called BladeX](https://github.com/spatie/laravel-blade-x). 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](https://github.com/spatie/laravel-html), or use Blade's [`@include`](https://laravel.com/docs/5.7/blade#including-sub-views) or [`@component`](https://laravel.com/docs/5.7/blade#components-and-slots) 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](https://spatie.be) we have used a combination of them all.

In particular we like Blade's `@component` directive. [Inspired by Vue](https://twitter.com/taylorotwell/status/797206788739309568), 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](https://github.com/spatie/laravel-blade-x) 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](https://twitter.com/daraghoshea/status/1045943244805287936) [fellow](https://twitter.com/marcelpociot/status/1045930138658123776) [devs](https://twitter.com/tnorthcutt/status/1046023164029878273) 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](https://github.com/spatie/laravel-blade-x/blob/50a14ad128ba1e5f09885bc115570c564be60aaf/src/BladeXServiceProvider.php#L15-L17) with our own [BladeXCompiler](https://github.com/spatie/laravel-blade-x/blob/50a14ad128ba1e5f09885bc115570c564be60aaf/src/BladeXCompiler.php). The `BladeXCompiler` [loops over](https://github.com/spatie/laravel-blade-x/blob/50a14ad128ba1e5f09885bc115570c564be60aaf/src/BladeXCompiler.php#L20) all registered components. That class contains [two](https://github.com/spatie/laravel-blade-x/blob/master/src/BladeXCompiler.php#L30) [regexes](https://github.com/spatie/laravel-blade-x/blob/master/src/BladeXCompiler.php#L61), carefully crafted by [Alex](https://twitter.com/alexvanderbist) and [Seb](https://twitter.com/sebdedeyne), 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](https://spatie.be) 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](https://github.com/spatie/laravel-blade-x#credits) 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](https://github.com/spatie/laravel-permission), [laravel-medialibrary](https://github.com/spatie/laravel-medialibrary) or [laravel-backup](https://github.com/spatie/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](https://www.northmeetssouth.audio/48) [Jacob](https://twitter.com/jacobbennett) and [Michael](https://twitter.com/michaeldyrynda) discussed BladeX and shared some interesting ideas for it. We are going to investigate some integration with our [laravel-view-components](https://github.com/spatie/laravel-view-components) and/or [Laravel's native view composers](https://laravel.com/docs/5.7/views#view-composers) to easily transform and fetch data before it gets passed into the component.

If you like [BladeX](https://github.com/spatie/laravel-blade-x) go take a look at [all the other open source packages](https://spatie.be/open-source/packages) our team has made previously. If you like our work, consider supporting us [via Patreon](https://www.patreon.com/spatie).

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](https://github.com/spatie/laravel-blade-x), [laravel-query-builder](https://github.com/spatie/laravel-query-builder), [laravel-view-models](https://github.com/spatie/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](https://github.com/spatie/laravel-blade-x).