Laravel components provides a means to extract some parts of a web application into reusable chunks. In this post we will learn how to create and blade components in laravel 8.
If you worked with Front-end frameworks before like Vuejs you might have see how components work in such frameworks. The components concept in laravel is the same. you may have encountered the laravel components in previous versions of Laravel, but it has little features. With the release of Laravel 8 the components has more features than before and provides a convenient way to write more cleaner code.
There are two types of components in laravel 8:
- Class based components.
- Anonymous components.
- Inline components.
Class Based Components
In the class based components approach the component has two files a PHP class located in App/View/Components directory and a view file located in resources/views/components directory. To create such component you can use the artisan command like so:
php artisan make:component LatestPosts
Once running this command you will see two files created, which are app/View/Components/LatestPosts.php and resources/views/components/latest-posts.blade.php.
app/View/Components/LatestPosts.php
<?php namespace App\View\Components; use Illuminate\View\Component; class LatestPosts extends Component { /** * Create a new component instance. * * @return void */ public function __construct() { } /** * Get the view / contents that represent the component. * * @return \Illuminate\Contracts\View\View|string */ public function render() { return view('components.latest-posts'); } }
resources/views/components/latest-posts.blade.php
<div> latest posts will be displayed here </div>
To display the component in your blade template we can call it using a custom <x-{component name}/> tag syntax. For example to display the latest posts component:
<x-latest-posts />
Now let’s see how to pass data to the component. Imagine this component render a list of posts coming from database, in our case i will just add a simple array for demonstration purposes. To accomplish that you have to define the data as public properties in the component class like so:
class LatestPosts extends Component { public $latestPosts; public function __construct($latestPosts) { $this->latestPosts = $latestPosts; } }
Any public property defined in the component class made available to the view provided that you inject those properties into the constructor as shown above.
Next update your component definition tag to allow accept the latestPosts attribute using :latestPosts syntax:
<x-latest-posts :latestPosts="$posts" />
As you see to send dynamic data the attribute name must begin with : then the attribute name. In this example i assigned the variable $posts to :latestPosts so we need to define the $posts variable in the controller that renders the template assuming the HomeController.
HomeController.php
<?php namespace App\Http\Controllers; class HomeController extends Controller { public function index() { $posts = [ [ "title" => "What is Lorem Ipsum?", "content" => "orem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book" ], [ "title" => "Why do we use it?", "content" => "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English" ] ]; return view('welcome')->with('posts', $posts); } }
Update the LatestPosts component view file like so:
resources/views/components/latest-posts.blade.php
<div> @foreach($latestPosts as $post) <article> <h3>{{$post['title']}}</h3> <p>{{$post['content']}}</p> </article> @endforeach </div>
Now you will see the posts in the browser. But you might ask if it possible to pass the data in the component’s render() method, in fact you can do this if you wish and it will work.
In addition to that any public method defined in the component is also accessible in the component view. For example Let’s format the content in the above snippet to take a substring only from the text.
So add this method in app/View/Components/LatestPosts.php
public function format($content) { return substr($content, 0, 100) . "..."; }
Then invoke this method in the view using the method as a variable like so:
resources/views/components/latest-posts.blade.php replace this line
<p>{{ $post['content'] }}</p>
With
<p>{{ $format($post['content']) }}</p>
Component Nesting
As with components in Vuejs or Reactjs if you to want to call a component from a parent component, you can achieve this easily in laravel components too. A good scenario for this is to render a list of items so each item is in fact a component that render a single item.
To clarify this let’s create a component to display just one post so in the terminal run this command to generate the component:
php artisan make:component Post
Now open the Post component class we just created and update it as shown:
app/View/Components/Post.php
<?php namespace App\View\Components; use Illuminate\View\Component; class Post extends Component { public $post; public function __construct($post) { $this->post = $post; } public function format($content) { return substr($content, 0, 100) . "..."; } public function render() { return view('components.post'); } }
As you see i declared the $post property and injected it in the constructor. The $post variable represent a single post item. In a real world example this represent a record from database.
Next update resources/views/components/post.blade.php
<article> <h3>{{ $post['title'] }}</h3> <p>{{ $format($post['content']) }}</p> </article>
Then update resources/views/components/latest-posts.blade.php
<div> @foreach($latestPosts as $post) <x-post :post="$post" /> @endforeach </div>
As you see i called the component in the same way as the latest posts component using <x-post /> passing in the :post attribute.
Notice that i added the format() method in the Post class so you have to remove it from the LatestPosts component class as it’s now longer needed there.
If you run this code you will see the same output as earlier.
Component Slots
Another nice feature in laravel component is slots. A slot represent a section you define in the component view and this slot is filled when you invoke this component in the template, this is the same as the @yield keyword in templates.
In the previous example let’s add a slot to the LatestPosts component so that we can display page header i.e “Latest Posts”:
resources/views/components/latest-posts.blade.php
<div> {{ $slot }} @foreach($latestPosts as $post) <x-post :post="$post" /> @endforeach </div>
As you see the slot defined by echoing the $slot variable. $slot is a special variable in laravel used to display the slot. Then to pass the content updated the component tag as shown:
<x-latest-posts :latestPosts="$posts"> <h2>Latest Posts</h2> </x-latest-posts>
In this code i changed <x-latest-posts /> self closing as shown above and injected the <h2>, this h2 will be substituted into the $slot we defined in the component.
What about if we want to display more slots into different locations in the component. In this case we will give the slots a name. in our example we can add another slot to display for example the pagination links like so:
resources/views/components/latest-posts.blade.php
<div> {{ $slot }} @foreach($latestPosts as $post) <x-post :post="$post" /> @endforeach {{ $pagination }} </div>
To specify the slot in the template we can use the <x-slot name=”name”> tag like this:
<x-latest-posts :latestPosts="$posts"> <h2>Latest Posts</h2> <x-slot name="pagination"> <ul> <li><a href="#">1</a> </li> <li><a href="#">2</a> </li> <li><a href="#">3</a> </li> </ul> </x-slot> </x-latest-posts>
So i specified <x-slot name=”pagination”> and in the component i printed the slot name “$pagination” as a variable. Note that the default $slot variable is still used for the default slot.
Anonymous Components
The anonymous components is such components that have only a view file without a class. These components places in the same components view at resources/views/components. To pass attributes to anonymous components you must specify them using the @props directive in the top of the component file.
So if we changed the previous example component to anonymous component we should do this:
resources/views/components/latest-posts.blade.php
@props(['latestPosts']) <div> @foreach($latestPosts as $post) <x-post :post="$post" /> @endforeach </div>
Then invoke the component is the usual way:
<x-latest-posts :latestPosts="$posts"></x-latest-posts>
The @props directive accept an array of the attribute names.
Inline Components
The inline components used for simple components. With the inline components there isn’t a view file only a class and the render method return the component markup directly.
To generate inline component specify –inline:
php artisan make:component MessageBox --inline
public function render() { return <<<'blade' <div class="message success"> {{ $slot }} </div> blade; }
some problem https://prnt.sc/1budp1u, https://prnt.sc/1bue1av