Laravel Form Components to rapidly build forms with Tailwind CSS and Bootstrap 4

I've always been a big fan of the Bootstrap framework, from the first version on. It's a great way to rapidly build interfaces and prototypes. These days we've mostly moved away from it towards Tailwind CSS, but it's still a great framework. Adam Wathan, the creator of the Tailwind framework, had a great package to work with Bootstrap forms in Laravel applications. It had awesome features like automatic validation state and model binding. Tailwind doesn't include default styling for forms, but there is an additional plugin called Tailwind CSS Custom Forms that provides a great starting point for form elements that still can be customized.

Ever since using Tailwind CSS, I've been looking for ways to generate forms as elegant as the Bootforms package. I've found myself using Blade components a lot, and I started to experiment with ways to configure and style forms in different projects. Meanwhile, Blade components got a massive upgrade in Laravel 7. They are now class-based, and you can use a Vue-like syntax.

We're planning to keep using Tailwind CSS, so it was evident that extracting the form elements was gonna some us time in the future. I wanted to incorporate the things I loved about Bootforms as well: validation and model binding. Every project needs a different kind of style, so I wanted to achieve maximum flexibility and straightforward customization. Let's take a look at the core features of this package, which you can find on GitHub:

  • The Blade views are independent of the component logic. In fact, the Tailwind and Bootstrap views use the same logic.
  • Built-in Tailwind CSS and Bootstrap 4 templates.
  • Model binding, validation, and re-population of old data.

Imagine a form to update a user's profile, set a tweet of the day, and two dummy checkboxes. In this example, I'll bind the user model to the first and second elements, provide the select element its options, and put the checkboxes in an inline group with a default value.

<x-form class="max-w-lg">
@bind($user)
<x-form-input name="username" label="Your username" />
<x-form-select name="language" :options="$languages" label="Preferred language" />
@endbind
 
<x-form-textarea name="tweet_of_the_day" placeholder="What's happening?" />
 
<x-form-group label="Supported frameworks" inline>
<x-form-checkbox name="bootstrap_support" default="true" label="Bootstrap 4" />
<x-form-checkbox name="tailwind_css_support" :default="get_tailwind_support()" label="Tailwind CSS" />
</x-form-group>
 
<x-form-submit />
</x-form>

The great thing about Blade components is the handling of attributes. The use of PHP expressions and variables (those prefixed with a colon) is a neat way to set defaults and select options. Another great use is localization. To localize a label you could use something like :label="__('user.username')". Additional attributes are passed down to the form element, the placeholder attribute is an example of that, as well as the class attribute on the x-form element.

Laravel Form Components

For me, the most essential aspect of this package is the separation of the component logic and the views. The logic handles features like model binding, validation, default data, and old data. There's more than one way to customize the components of this package:

  • There is a configuration setting to switch UI frameworks. The package comes with Tailwind CSS and Bootstrap templates, their feature set is virtually the same.
  • You can publish the component views with the vendor:publish artisan command and start customizing them from your resources folder.
  • The component classes and templates are bound in the configuration file. This means you can decouple our logic for each form element, and attach your own component class to it. Or you can use our logic and use a completely different template.

Below you'll find an excerpt from the configuration file.

return [
'prefix' => '',
 
'framework' => 'tailwind',
 
'components' => [
'form-input' => [
'view' => 'form-components::{framework}.form-input',
'class' => \ProtoneMedia\LaravelFormComponents\Components\FormInput::class,
],
 
...
],
];

But that's not all of it! It supports Laravel Livewire with its real-time validation features, and there is support for the Spatie's popular translation package. There is extensive documentation available, and the package requires no additional dependencies. Check it out on GitHub!

Update January 19, 2021: I'm working on a Pro version of this package!