Here's an example of a single form field from the default login.blade.php view:

<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
    <label for="email" class="col-md-4 control-label">E-Mail Address</label>

    <div class="col-md-6">
        <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>

        @if ($errors->has('email'))
            <span class="help-block">
                <strong>{{ $errors->first('email') }}</strong>
            </span>
        @endif
    </div>
</div>

This is massive. Imagine having 5-10 inputs like this in a single view file? Not only does it look gross for something as simple as an input field, it is also hard to read and is error prone. To add a new field you'd probably copy an existing block and then manually rename all the instances of email to, say, username - easy to make a mistake or to miss something there.

We can't strip this HTML since this is all essential for the field to look and work right. What we can do though is extract this to a Blade component and make it more general.

Let's do exactly that. Let's create a folder to store our components, for example resources/views/components/form. Then create a file inside that folder called input.blade.php. Grab the HTML above and paste it in.

We'll start by replacing all the occurrences of email to a variable called $name. This is the result:

<div class="form-group{{ $errors->has($name) ? ' has-error' : '' }}">
    <label for="{{ $name }}" class="col-md-4 control-label">E-Mail Address</label>

    <div class="col-md-6">
        <input id="{{ $name }}" type="email" class="form-control" name="{{ $name }}" value="{{ old($name) }}" required autofocus>

        @if ($errors->has($name))
            <span class="help-block">
                <strong>{{ $errors->first($name) }}</strong>
            </span>
        @endif
    </div>
</div>

Now let's make the label editable and optional:

@if (isset($label))
    <label for="{{ $name }}" class="col-md-4 control-label">{{ $label }}</label>
@endif

The type of the input should be flexible as well with text being the default. The placeholder should be optional. This is what the input element should look after these modifications:

<input id="{{ $name }}" 
    type="{{ isset($type) ? $type : 'text' }}"
    class="form-control"
    name="{{ $name }}"
    placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
    value="{{ old($name) }}" required autofocus>

required autofocus should be removed as well to make the component more generic. Instead, we're going to add a variable called attributes to provide the ability to add any additional attributes we might need.

<input id="{{ $name }}" 
    type="{{ isset($type) ? $type : 'text' }}"
    class="form-control"
    name="{{ $name }}"
    placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
    value="{{ old($name) }}"
    {{ isset($attributes) ? $attributes : '' }}>

This is already great, but I'd like to work on the value attribute a little bit more. We'll accept a value from a Model object if there is an object passed to the component. This allows us to use the same component (and ultimately the same view) for both create and edit forms.

<input id="{{ $name }}" 
    type="{{ isset($type) ? $type : 'text' }}"
    class="form-control"
    name="{{ $name }}"
    placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
    value="{{
        old($name) ?: (isset($object) ? $object->{$name} : '')
    }}"
    {{ isset($attributes) ? $attributes : '' }}>

What we do here is we set the value to the old() value if there's any. If there is none, we're trying to get the value from the provided object, otherwise we're setting the value to an empty string.

Finally, this is the complete result:

<div class="form-group{{ $errors->has($name) ? ' has-error' : '' }}">
    @if (isset($label))
        <label for="{{ $name }}" class="col-md-4 control-label">{{ $label }}</label>
    @endif

    <div class="col-md-6">
        <input id="{{ $name }}" 
            type="{{ isset($type) ? $type : 'text' }}"
            class="form-control"
            name="{{ $name }}"
            placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
            value="{{
                old($name) ?: (isset($object) ? $object->{$name} : '')
            }}"
            {{ isset($attributes) ? $attributes : '' }}>

        @if ($errors->has($name))
            <span class="help-block">
                <strong>{{ $errors->first($name) }}</strong>
            </span>
        @endif
    </div>
</div>

Let's go back to our login.blade.php view. We can now replace the old HTML block with the email input with this:

@component('components.form.input', [
    'name' => 'email',
    'label' => 'E-Mail Address',
])@endcomponent

Looks much nicer, more readble, and way more compact, doesn't it?

Another example. Imagine we have a single view file edit.blade.php for creating and editing blog posts. You have to pass a $post variable to this view in both create and edit methods of the controller, except there's no post in the create method yet so you should simply pass null. This is what the component for the title field could look like:

@component('components.form.input', [
    'name' => 'title',
    'label' => 'Title',
    'placeholder' => 'Enter the title of the blog post',
    'object' => $post,
])@endcomponent

Final Words

Hopefuly you have an understanding of how Blade components and the whole process work now. You can further modify our component according to your needs. Based on this component you can easily create components for other form elements like textarea or checkbox - I'm leaving this up to you.