Scout APM is PHP application performance monitoring designed for developers. With tracing logic that ties issues back to the line of code causing them, you can pinpoint n+1 queries, memory leaks, and other abnormalities in real time so you can knock them out and get back to building a great product. Start your free 14-day trial today and get the performance insight you need in less than 4 minutes.

Some cool Laravel 7 Blade components

Original – by Freek Van der Herten – 3 minute read

One of my favourite new features of Laravel 7 are Blade components. The allow you to define custom html tags that are backed by Blade partials. In this blogpost I'd like to show you a couple very handy components.

This blogpost assumes that you already know how you can use Blade components.

The form button

When, in an app, you want to direct a user to an action that has side effects, you mustn't use a simple link. Accepting GET requests for actions would make make CSRF attacks very trivial to pull off.

Instead, you should use a different HTTP verb, use a form and CSRF token. Here's a FormButton component that generates a button in a form.

{{-- content of formButton.blade.php --}}
<form method="POST" action="{{ $action }}">
    @csrf
    @method($method ?? 'POST')
        <button
            type="submit"
            class="{{ $class ?? '' }}"
        >
            {{ $slot }}
        </button>
</form>

You can use it like this.

// perform an action
<x-form-button :action="route('doSomething')">
   Do something
</x-form-button>

// perform an action with another HTTP verb
<x-form-button :action="route('model.delete', $model)" method="delete">
   Delete model
</x-form-button>

The navigation item

Almost any application needs to display some kind of navigation, like menus or tabs. It's always nice that these navigation links have an active state so users know in which part of the app they are.

Here's the navigationLink Blade component that can render a link. It automatically sets itself active when its URL starts with the URL of the current request.

{{-- content of navigationLink.blade.php --}}
<li class="{{ \Illuminate\Support\Str::startsWith(request()->url(), $href) ? 'active' : ''  }}">
    <a href="{{ $href }}" @isset($dataDirtyWarn) data-dirty-warn @endisset>
        {{ $slot }}
    </a>
</li>

Here's how it is used in the mailcoach.app codebase.

 <nav class="tabs">
        <ul>
            <x-navigation-item :href="route('mailcoach.emailLists.subscribers', $emailList)">
                <x-icon-label icon="fa-users" text="Subscribers" :count="$emailList->subscribers()->count() ?? 0" />
            </x-navigation-item>
            <x-navigation-item :href="route('mailcoach.emailLists.tags', $emailList)">
                <x-icon-label icon="fa-tag" text="Tags" />
            </x-navigation-item>
            <x-navigation-item :href="route('mailcoach.emailLists.segments', $emailList)">
                <x-icon-label icon="fa-chart-pie" text="Segments" />
            </x-navigation-item>
            <x-navigation-item :href="route('mailcoach.emailLists.settings', $emailList)">
                <x-icon-label icon="fa-cog" text="Settings" />
            </x-navigation-item>
        </ul>
    </nav>

This is how that is rendered.

screenshot

Form elements

Blade components are a natural fit for rendering form elements. Let's take a look at the textField component used in Mailcoach.

<div class="form-row">
    @if($label ?? null)
    <label class="{{ ($required ?? false) ? 'label label-required' : 'label' }}" for="{{ $name }}">
        {{ $label }}
    </label>
    @endif
    @error($name)
        <p class="form-error" role="alert">{{ $message }}</p>
    @enderror
    <input
        autocomplete="off"
        type="{{ $type ?? 'text' }}"
        name="{{ $name }}"
        id="{{ $name }}"
        class="input"
        placeholder="{{ $placeholder ?? '' }}"
        value="{{ old($name, $value ?? '') }}"
        {{ ($required ?? false) ? 'required' : '' }}
    >
</div>

As you can see, it renders the label, form field and possibly, the error. This is how it is used.

<x-text-field label="Name" name="name" required />

In closing

At Spatie we've been using Blade components for quite some time through our, now retired, BladeX package. We're very happy that Laravel 7 now support this functionality out of the box.

If you want to see more examples of Blade components we use, consider registering a Mailcoach license. There are plenty of other cool components to discover in the source code.

screenshot

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.

Comments

Webmentions

Roman Pronskiy liked on 4th April 2020
Yemil Godinez liked on 3rd April 2020
Uchok 🌸 liked on 3rd April 2020
Ryan Chandler liked on 3rd April 2020
im.mister.j liked on 3rd April 2020
Levente Balogh-Korodi liked on 3rd April 2020
Bee business liked on 3rd April 2020
Liam Hammett liked on 3rd April 2020
StoicDojo liked on 3rd April 2020
ninjaparade liked on 3rd April 2020
Jesse AI liked on 3rd April 2020
ali ali liked on 3rd April 2020
Wyatt liked on 3rd April 2020
Stijn Vanouplines liked on 3rd April 2020
assoftTR liked on 3rd April 2020
Indra 印洞羅 liked on 3rd April 2020
Liam Hammett replied on 3rd April 2020
For example, multiple forms with the same input name on one page will lead to multiple of the same IDs. You should be able to manually override the ID when you need to. You might want to account for names like "email[]" for array-based forms.
Ryan Chandler replied on 3rd April 2020
Hm, fair enough.
Freek Van der Herten replied on 3rd April 2020
Domains mostly only contain business logic. Views (and Livewire components) are put in app/Http, not in app/Domain
Liam Hammett replied on 3rd April 2020
Interesting to see that you also went with the approach to use the name for the ID on input components, I do similar myself for convenience. That said, it's not foolproof and can really easily catch you out and cause problems with such a simple implementation
Ryan Chandler replied on 3rd April 2020
If you've got domain specific class-based components, are you still putting the classes inside of your domain folder and manually registering or putting them in the default app/View/Components/{domain} folder?
बेद retweeted on 3rd April 2020
Florian Beer liked on 3rd April 2020
Cofe Ding liked on 2nd April 2020
kronos_I retweeted on 2nd April 2020
PHP Synopsis retweeted on 2nd April 2020
Mak Man liked on 2nd April 2020
Mike liked on 2nd April 2020
tema gildas liked on 2nd April 2020
Lennart Fischer liked on 2nd April 2020
Hadyan Ahmad liked on 2nd April 2020
Travis Elkins liked on 2nd April 2020
togo liked on 2nd April 2020
Andy Hinkle liked on 2nd April 2020
Faisal ahmed liked on 2nd April 2020
Carl Brand liked on 2nd April 2020
Nuno Souto liked on 2nd April 2020
Liam Seys replied on 2nd April 2020
Thanks!