Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the astra-sites domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/u162105626/domains/phptechtutor.com/public_html/wp-includes/functions.php on line 6121

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the rank-math domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/u162105626/domains/phptechtutor.com/public_html/wp-includes/functions.php on line 6121

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the rank-math domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/u162105626/domains/phptechtutor.com/public_html/wp-includes/functions.php on line 6121

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the wpforms-lite domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/u162105626/domains/phptechtutor.com/public_html/wp-includes/functions.php on line 6121

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the astra domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/u162105626/domains/phptechtutor.com/public_html/wp-includes/functions.php on line 6121
Laravel Form Components - PHPTechTutor

Laravel Form Components

Brief Introduction

Here in this article, we will design some basic laravel form components which will give you all the aspects of laravel components as well as dynamic attributes so you have an idea about it with good laravel component examples.

What is a component?

A component is an independent, reusable and isolated single UI block. Components are always a great choice to divide the large UI into small chunks. Dynamic attributes are the main hero of any component. DRY(Don’t Repeat Yourself) with less code complexity is the main advantage to use components. So always design a component in a scaler way because we will reuse it in multiple ways.

Laravel Components are as same as sections, layouts, and includes but it is easier to understand and derive with more functionalities and flexibilities. Where we can easily modify with the dynamic attributes. There are two types of components, class-based components and anonymous components. In form components, we will mainly use anonymous components.

The Anonymous component is the component that has only a blade template with no class. Here is a command to create the anonymous component,

php artisan make:component <component-name> --view

As an example, If we want to create the component for the navbar then we have to fire,

php artisan make:component navbar --view

So it will create the blade template under the /resources/views/components folder. I hope you will get the basics now let’s dive into the form components.

Creating Laravel Application

We will start by creating a new Laravel application if you have already then you can skip this section. Open your command line terminal and run the below command to create a Laravel project using composer.

composer create project laravel/laravel form-components

Installing Laravel Breeze

We will use the default Laravel Breez to install the authentication features. This will give us a default environment for login, registration, password reset, email verification, and password confirmation. Laravel Breeze’s default view layer is made up of simple Blade templates styled with Tailwind CSS. Here are the necessary commands to start with Laravel Breeze,

composer require laravel/breeze --dev

php artisan breeze:install

Migrate Database

Add your database configurations in the .env file and fire the migration command to migrate the database,

php artisan migrate

Creating Form Components

We will create the form component in the respective forms directory. So the path will be /resources/views/components/forms. When you fire the command it will create a new component in the forms directory.

The dot is always used to create the nested directories so if you want two nested directories then the command will be directory1.directory2.component and it will create the component as /resources/views/components/directory1/directory2/component.blade.php.

We will render the component as <x-directory.component />. Where the directory is optional if there is no directory then it will be as <x-component />. The component tag starts from x- and is followed by the kebab case of the component name. As I mentioned earlier the dynamic attributes are the hero of any component. So here to define dynamic attributes we will use the colon(:) syntax. Everything starts with a colon considered as the dynamic attribute. In the dynamic attribute, you can directly write the laravel code because it is kind of a variable.

The HTML attributes are default available in the component as variables. So if you pass the label then we have $label defaults in a component.

Here the catch is the attribute bag, it will contain all the HTML attributes in the $attributes array as well as the extra attributes which you want to pass. The important thing is you can merge the additional values with the existing attribute values. Here is a good example of that,

Alert Component

<div {{ $attributes->merge(["class" => "p-4 font-bold text-lg alert"]) }}>
    {{ $message }}
</div>

You can now merge the additional classes according to the conditions,

<x-alert class="alert-success" :message="$message" />
<x-alert class="alert-danger" :message="$message" />
<x-alert class="alert-warning" :message="$message" />

In this way, you can merge any attributes with dynamic values as well as you can define new attributes on the top of components with the help of the @props directive. I am not a fan of @prop because if we want to use it then we have to define all the dynamic attributes in props. It will not merge the new @props attributes with the attribute bag. But obviously, we need to use it in some conditional logic.

Here is a good example of a @prop directive,

@props([
    "alertType" => "alert-primary", 
    "message"
])

<div {{ $attributes->merge(["class" => "p-4 font-bold text-lg alert ".$alertType]) }}>
    {{ $message }}
</div>

But as I mention it will not default merge to the attributes bag so we also have to at least define the message with alertType too.

Now I think we are good to go to explore the different types of components. Here are some Anonymous Form Components which are based on tailwind CSS. You can just download and use it in your way.

Text Field Component

php artisan make:component forms.text-field --view

<div>
    <label 
        for="{{ $name }}" 
        class="{{ ($required ?? false) ? 'after:content-["*"]' : '' }} block font-medium text-sm text-gray-700">
        {{ $label }}
    </label>

    <input 
        type="{{ $type ?? 'text' }}" 
        placeholder="{{ $placeholder ?? '' }}" 
        value="{{ old($name, $value ?? false) }}" 
        id="{{ $name }}"
        {{ ($required ?? false) ? 'required' : '' }}
        {{ $attributes->merge(['class' => 'block mt-1 w-full rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50']) }}
    >
    
    @error($name)
        <p class="text-sm text-red-600 mt-1" role="alert">{{ $message }}</p>
    @enderror
</div>

<x-forms.text-field 
    label="Full Name" 
    name="name" 
    placeholder="Please Enter Your Full Name"
    :value="$user->name"
    required
/>

Select Field Component

php artisan make:component forms.select-field --view

<div>
    <label 
        for="{{ $name }}" 
        class="{{ ($required ?? false) ? 'after:content-["*"]' : '' }} block font-medium text-sm text-gray-700">
        {{ $label }}
    </label>

    <select 
        name="{{ $name }}" 
        id="{{ $name }}"
        class="block mt-1 w-full rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
    >
        @isset($placeholder)
            <option value="">{{ $placeholder }}</option>
        @endisset

        @foreach ($options as $optionKey => $optionValue)
            <option 
                value="{{ $optionKey }}" 
                @if(in_array($optionKey, $disableOptions)) disabled @endif
                @if(old($name, $value ?? false) == $optionKey) selected @endif
            >{{ $optionValue }}</option>
        @endforeach
    </select>

    @error($name)
        <p class="text-sm text-red-600 mt-1" role="alert">{{ $message }}</p>
    @enderror
</div>

<x-forms.select-field 
    label="Country"
    name="country"
    placeholder="Please select country"
    :options="[
        '91' => 'India',
        '44' => 'UK',
        '1' => 'USA'
    ]"
    :disableOptions="[
        '44'
    ]"
    :value="$user->country"
/>

Checkbox Component

php artisan make:component forms.checkbox --view

@php
    $selectedOptions = old(str_replace('[]', '', $name), $value ?? false) ?? []
@endphp

<div>
    <label 
        class="{{ ($required ?? false) ? 'after:content-["*"]' : '' }} block font-medium text-sm text-gray-700"
    >{{ $label }}</label>
    
    <div>
        @foreach ($options as $option)
            <input 
                type="checkbox" 
                name="{{ $name }}" 
                value="{{ $option['value'] }}"
                @if(is_array($selectedOptions) && in_array($option['value'], $selectedOptions)) checked @endif
            >
            <label 
                class="font-medium text-sm text-gray-700 {{ ($option['class'] ?? false) ? $option['class'] : '' }}"
            >{{ $option['label'] }}</label><br>
        @endforeach
    </div>

    @error($name)
        <p class="text-sm text-red-600 mt-1" role="alert">{{ $message }}</p>
    @enderror
</div>

<x-forms.checkbox 
    label="Hobbies"
    name="hobbies[]"
    :options="[
        ['label' => 'Singing', 'value' => 'singing', 'class' => 'text-red-700'],
        ['label' => 'Travelling', 'value' => 'travelling'],
        ['label' => 'Reading', 'value' => 'reading'],
    ]"
    :value="$user->hobbies"
/>

Radio Component

php artisan make:component forms.radio --view

@php
    $checked = old($name, $value ?? null) == $optionValue;
@endphp

<input 
    type="radio"
    id="{{ $optionValue }}" 
    name="{{ $name }}" 
    value="{{ $optionValue }}"
    @if($checked) checked @endif
/>  
<label 
    for="{{ $optionValue }}" 
    class="font-medium text-sm text-gray-700"
>{{ $label }}</label><br>

<x-forms.radio
    label="Male"
    name="gender"
    :option-value="'male'"
    :value="$user->gender"
/>
<x-forms.radio
    label="Female"
    name="gender"
    :option-value="'female'"
    :value="$user->gender"
/>

Textarea Component

php artisan make:component forms.textarea --view

<div>
    <label 
        for="{{ $name }}" 
        class="{{ ($required ?? false) ? 'after:content-["*"]' : '' }} block font-medium text-sm text-gray-700">
        {{ $label }}
    </label>
    
    <div>
        <textarea 
            id="{{ $name }}" 
            name="{{ $name }}" 
            rows="10" 
            {{ $attributes->merge(['class' => 'block mt-1 w-full rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50']) }}
        >{{ old($name, $value ?? false) }}</textarea>
    </div>

    @error($name)
        <p class="text-sm text-red-600 mt-1" role="alert">{{ $message }}</p>
    @enderror
</div>

<x-forms.textarea
    label="About"
    name="about"
    :value="$user->about"
/>

Button Components

Form Button

<form
    method="POST"
    action="{{ $action }}"
>
    @csrf
    @method($method ?? 'POST')
        <button
            type="submit"
            class="{{ $class ?? '' }}"
        >
            {{ $slot }}
        </button>
</form>

Primary/Submit Button

<button 
    {{ $attributes->merge(['type' => 'submit', 'class' => 'btn btn-primary']) }}
>{{ $slot }}</button>

Cancel Button

<a
    href="{{ $redirectTo ?? 'javascript:void(0)' }}"
    {{ $attributes->merge(['class' => 'underline text-sm text-gray-600 hover:text-gray-900']) }}
>
    {{ $label ?? __('Cancel') }}
</a>

Here in the checkbox component, I make it whole as a component where we have to pass options as an array. But instead, we can also make the single option component.

As vice versa for the radio. I make it as an individual option component instead to create the whole at once.

Do comment in the comment section and let me know what you think. Which option will be flexible, scalable and obviously with less code? Other options are also welcome.

Leave a Comment

Your email address will not be published. Required fields are marked *