<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Newns</title>
    <description>The latest articles on DEV Community by Daniel Newns (@dannewnsjump24).</description>
    <link>https://dev.to/dannewnsjump24</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F713086%2F2aee52f5-4067-4d17-a7f0-fc7fb093655a.jpeg</url>
      <title>DEV Community: Daniel Newns</title>
      <link>https://dev.to/dannewnsjump24</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dannewnsjump24"/>
    <language>en</language>
    <item>
      <title>Laravel Blade Components</title>
      <dc:creator>Daniel Newns</dc:creator>
      <pubDate>Sun, 28 May 2023 09:46:28 +0000</pubDate>
      <link>https://dev.to/jump24/laravel-blade-components-3hbh</link>
      <guid>https://dev.to/jump24/laravel-blade-components-3hbh</guid>
      <description>&lt;p&gt;&lt;a href="https://laravel.com/docs/10.x/blade"&gt;Laravel Blade&lt;/a&gt; is a powerful templating engine that allows developers to create dynamic and reusable views in a Laravel application. One of the key features of Blade is the ability to create reusable and composable components, which can help speed up front-end development. By enabling the creation of reusable components that provide consistent styles and behaviour, developers can avoid the need to construct elements from scratch. Instead, they can simply make use of the components that already exist.&lt;/p&gt;

&lt;p&gt;In this article we will create a basic form that shows you some benefits and techniques of blade components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your first component
&lt;/h2&gt;

&lt;p&gt;There are two types of components: class-based and anonymous. Class-based components have a class and a view template, while anonymous components only have a view template. In most cases, anonymous components are sufficient, and I tend to use class-based components only when I need to use dependency injection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component layouts.app --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the above command will create our first component, a layout file named resources/views/components/layouts/app.blade.php. This file will be the layout of the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/layouts/app.blade.php --&amp;gt;

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="{{ str_replace('_', '-', app()-&amp;gt;getLocale()) }}"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="utf-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1"&amp;gt;

    &amp;lt;title&amp;gt;Laravel Blade Components&amp;lt;/title&amp;gt;

    &amp;lt;script src="https://cdn.tailwindcss.com"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    {{ $slot }}
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&amp;lt;!-- /resources/views/example.blade.php --&amp;gt;

&amp;lt;x-layouts.app&amp;gt;
    Hello World!
&amp;lt;/x-layouts.app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;{{ $slot }}&lt;/code&gt; will render whatever we pass to it. For example, passing Hello World! will render it on the page. Slots are what make blade components composable. We can pass components to other components and even use &lt;a href="https://laravel.com/docs/10.x/blade#slots"&gt;named slots&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a form
&lt;/h2&gt;

&lt;p&gt;Run the following to create our anonymous index component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component form.index --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally to group components together you would have to have a form component then have the rest of the forms components inside a folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/resources/views/components/form.blade.php
/resources/views/components/form/group.blade.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anonymous index components allow you to group your components together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/resources/views/components/form/index.blade.php
/resources/views/components/form/group.blade.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage would look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-layouts.app&amp;gt;
    &amp;lt;x-form&amp;gt;
        &amp;lt;x-form.group&amp;gt;
            Hello!
        &amp;lt;/xform.group&amp;gt;
    &amp;lt;/x-form&amp;gt;
&amp;lt;/x-layouts.app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/form/index.blade.php --&amp;gt;

@props([
    'method' =&amp;gt; 'POST',
    'action',
    'hasFiles' =&amp;gt; false,
])

&amp;lt;form
    method="{{ $method !== 'GET' ? 'POST' : 'GET' }}"
    action="{{ $action }}"
    {!! $hasFiles ? 'enctype="multipart/form-data"' : '' !!}
    {{ $attributes-&amp;gt;except(['method', 'action']) }}
&amp;gt;
    @csrf
    @method($method)

    {{ $slot }}
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define the props we want the component to accept. We are able to set some sensible defaults. Most forms have the method as &lt;code&gt;POST&lt;/code&gt; so we set that as default. When forms are sending files we need to have the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/enctype"&gt;enctype&lt;/a&gt; attribute. Instead of typing it out every time we make the component add this attribute on when we need it.&lt;/p&gt;

&lt;p&gt;We want to make sure the developer passes an action when using this component so we set action as a prop but set no default value. When no action is passed Laravel will throw an error if we do not do an &lt;code&gt;isset()&lt;/code&gt; check.&lt;/p&gt;

&lt;p&gt;Echoing out &lt;code&gt;$attributes&lt;/code&gt; allows us to pass any additional attributes we need without having to define them in the props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-form action="/users"&amp;gt;&amp;lt;/x-form&amp;gt;
&amp;lt;x-form :action="route('users.store')"&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form method="GET"&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form has-files&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form class="border border-red-200"&amp;gt;&amp;lt;/x-form&amp;gt;

&amp;lt;x-form 
    :action="route('photos.store')"
    has-files
    class="p-5"
&amp;gt;
    //
&amp;lt;/x-form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example we use the &lt;code&gt;:action&lt;/code&gt; attribute. We use the : prefix to denote that it is a PHP expression or variable. We could also do &lt;code&gt;:action="$someRoute"&lt;/code&gt;. If it is a hardcoded or primitive value we  do &lt;code&gt;action="/"&lt;/code&gt; like normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create text input
&lt;/h2&gt;

&lt;p&gt;When working with inputs I like to create a group component that can take the input component. This group will display the label, help text and any errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component input.group --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are setting a default class using &lt;code&gt;$attributes-&amp;gt;class(['block'])&lt;/code&gt;. If we were to pass the class attribute any classes would be merged with block.&lt;/p&gt;

&lt;p&gt;We use &lt;code&gt;@class()&lt;/code&gt; to conditionally set classes. &lt;code&gt;text-gray-700 inline-block mb-1&lt;/code&gt; is always displayed, &lt;code&gt;text-red-500&lt;/code&gt; is only merged into the default when &lt;code&gt;$error&lt;/code&gt; is present.&lt;/p&gt;

&lt;p&gt;If we don’t pass a prop in then it is not defined, that is why we use &lt;code&gt;@isset($help)&lt;/code&gt; and &lt;code&gt;@isset($error)&lt;/code&gt; to check if they are set. We could also set the props to have &lt;code&gt;null&lt;/code&gt; as their default value and check for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/input/group.blade.php --&amp;gt;

@props([
    'label',
    'for',
    'help',
    'error',
])

&amp;lt;label
    {{ $attributes }}
    {{ $attributes-&amp;gt;class(['block']) }}
    for="{{ $for }}"
&amp;gt;
    &amp;lt;span
        @class([
            'text-gray-700 inline-block mb-1',
            'text-red-500' =&amp;gt; isset($error)
        ])
    &amp;gt;{{ $label ?? '' }}&amp;lt;/span&amp;gt;
    &amp;lt;div class="mt-1"&amp;gt;
        {{ $slot }}
    &amp;lt;/div&amp;gt;
    @isset($help)
        &amp;lt;p class="mt-2 text-sm text-gray-500" id="{{ $for }}"&amp;gt;{{ $help }}&amp;lt;/p&amp;gt;
    @endif
    @isset($error)
        &amp;lt;div class="mt-1 text-red-500 text-sm"&amp;gt;{{ $error }}&amp;lt;/div&amp;gt;
    @endif
&amp;lt;/label&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we will create a text input&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component input.text --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component uses &lt;code&gt;@aware()&lt;/code&gt;. This allows the child component to &lt;a href="https://laravel.com/docs/10.x/blade#accessing-parent-data"&gt;access data in the parent component&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/input/text.blade.php --&amp;gt;

@aware([
    'error',
])

@props([
    'value',
    'name',
    'for',
])

&amp;lt;input
    {{ $attributes-&amp;gt;class([
        'shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md',
        'border-red-500' =&amp;gt; $error
    ]) }}
    @isset($name) name="{{ $name }}" @endif
    type="text"
    @isset($value) value="{{ $value }}" @endif
    {{ $attributes }}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create button
&lt;/h2&gt;

&lt;p&gt;Finally we can create a button to submit our form. We will use an anonymous index component again. This is because I don’t want to access the button directly, instead I want to use this component inside &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt; buttons.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:component button.index --view&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/button/index.blade.php --&amp;gt;

@aware([
    'type',
])

&amp;lt;button
    type="{{ $type }}"
    {{ $attributes-&amp;gt;class([
        'inline-flex items-center border font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2',
    ]) }}
&amp;gt;
    {{ $slot }}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we create our &lt;code&gt;primary&lt;/code&gt; button. You can see that we are using the &lt;code&gt;x-button&lt;/code&gt; inside our &lt;code&gt;primary&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:component button.primary --view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/button/primary.blade.php --&amp;gt;

@props([
    'type' =&amp;gt; 'button',
])

&amp;lt;x-button
    {{ $attributes-&amp;gt;merge(['class' =&amp;gt; 'border-transparent shadow-sm text-white bg-indigo-600 hover:bg-indigo-700']) }}&amp;gt;
    {{ $slot }}
&amp;lt;/x-button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Separating the &lt;code&gt;x-button&lt;/code&gt; component means that we can re-use it in multiple places, even using it on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;Now we have created our components we can start to use them together. We first use our form component to wrap all our inputs, in this instance we only need to pass the route as the action. Next we have a couple of input groups, these take a label, for and an error. The error comes from the &lt;a href="https://laravel.com/docs/10.x/validation#working-with-error-messages"&gt;validation error bag&lt;/a&gt; that is available to all views. Passed to the input groups slot is the input. In this example we are using automatic attributes to pass along the old value to the value attribute. Lastly we use our button to submit the form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-form :action="route('users.store')"&amp;gt;
    &amp;lt;x-input.group label="Email" for="email" :error="$errors-&amp;gt;first('email')"&amp;gt;
        &amp;lt;x-input.email name="email" :value="old('email')" /&amp;gt;
    &amp;lt;/x-input.group&amp;gt;
    &amp;lt;x-input.group label="Password" for="password" :error="$errors-&amp;gt;first('password')"&amp;gt;
        &amp;lt;x-input.password name="password" :value="old('password')" /&amp;gt;
    &amp;lt;/x-input.group&amp;gt;
    &amp;lt;x-button.primary&amp;gt;
      Submit
    &amp;lt;/x-button.primary&amp;gt;
&amp;lt;/x-form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can mix blade components with plain HTML as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-form action="/photo" has-files&amp;gt;
    &amp;lt;div class="p-3 border border-slate-200"&amp;gt;
      &amp;lt;x-input.group label="Password" for="photo" :error="$errors-&amp;gt;first('photo')"&amp;gt;
          &amp;lt;input type="file" name="photo" /&amp;gt;
      &amp;lt;/x-input.group&amp;gt;
      &amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/x-form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus Tips
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://laravel.com/docs/10.x/blade#short-attribute-syntax"&gt;Short Attribute Syntax&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{-- Short attribute syntax... --}}
&amp;lt;x-input.text $name /&amp;gt;

{{-- Is equivalent to... --}}
&amp;lt;x-input.text name="{{ $name }}" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://laravel.com/docs/10.x/blade#slots"&gt;Named Slots&lt;/a&gt; - You can have multiple slots in a component by giving them names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;x-modal&amp;gt;
    &amp;lt;x-slot:header&amp;gt;
      Hello World!
    &amp;lt;/x-slot&amp;gt;

    Some lovely content

    &amp;lt;x-slot:footer&amp;gt;
      Goodbye World!
    &amp;lt;/x-slot&amp;gt;
&amp;lt;/x-modal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’d achieve this by doing the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- /resources/views/components/modal/index.blade.php --&amp;gt;

&amp;lt;div&amp;gt;
  &amp;lt;header&amp;gt;
    {{ $header }}
  &amp;lt;/header&amp;gt;
  &amp;lt;main&amp;gt;
    {{ $slot }}
  &amp;lt;/main&amp;gt;
  &amp;lt;footer&amp;gt;
    {{ $footer }}
  &amp;lt;/footer&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>blade</category>
      <category>php</category>
    </item>
  </channel>
</rss>
