How to customize Laravel filament login page
Fazail Alam
Posted on August 15, 2022
Laravel filament is a set of tools from which you can rapidly build stack application. Currently it has 3 tools, Admin Panel, Form Builder and Table Builder. There are also community plugin to support Laravel filament.
TALL stack
Tall stack is full stack framework for laravel. It stands for T: Tailwindcss , A: Alpinejs , L: Laravel and L: Livewire.
Getting Started
I assume that you have already installed Laravel and Filament. If not than check here for setting up filament. First publish configuration and views of filament.
php artisan vendor:publish --tag=filament-config
php artisan vendor:publish --tag=filament-views
Generated Files:
/
|-- config/
| |-- filament.php
|-- resources/
| |-- views/
| |-- vendor/
| |-- filament/
| ...
| |-- login.blade.php
This will publish filament configuration and views.
Vite setup for filament
The current default bundler for laravel is vitejs, so if you have created a new project then there is greater chance that it came with vite. If it is then we have to register render hook head.end in register method of AppServiceProvider. We need to add @vite directive in order to use the compiled css and js files for our admin panel.
use Filament\Facades\Filament;
public function register()
{
Filament::registerRenderHook(
'head.end',
fn (): string => Blade::render('@vite([\'resources/css/app.css\',\'resources/js/app.js\'])'),
);
}
For the icons i am using Iconify, so we need to register cdn script for iconify.
public function boot()
{
Filament::registerScripts([
'https://code.iconify.design/2/2.2.1/iconify.min.js',
], true); // true means that this script will be load before filament core scripts.
}
We also need to use filament's tailwind configuration otherwise styling of the admin panel will not work. we can use tailwind's presets property to use preset configuration.
module.exports = {
...
presets: [require("./vendor/filament/filament/tailwind.config.js")],
}
Change login class
Since filament uses livewire component to render inputs of login form, we need to create our own class components. Copy the code of vendor/filament/filament/src/Http/Livewire/Auth/Login.php file then create a new file app/Filament/Auth/Login.php and paste the code in it. Next change the namespace of the class to namespace App\Filament\Auth;. Then pass the class into filament config file under auth.pages.login.
//app/Filament/Auth/Login.php
<?php
namespace App\Filament\Auth;
use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException;
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
use Filament\Facades\Filament;
use Filament\Forms\ComponentContainer;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Http\Responses\Auth\Contracts\LoginResponse;
use Illuminate\Contracts\View\View;
use Livewire\Component;
/**
* @property ComponentContainer $form
*/
class Login extends Component implements HasForms
{
use InteractsWithForms;
use WithRateLimiting;
public $email = '';
public $password = '';
public $remember = false;
public function mount(): void
{
if (Filament::auth()->check()) {
redirect()->intended(Filament::getUrl());
}
$this->form->fill();
}
public function authenticate(): ?LoginResponse
{
try {
$this->rateLimit(5);
} catch (TooManyRequestsException $exception) {
$this->addError('email', __('filament::login.messages.throttled', [
'seconds' => $exception->secondsUntilAvailable,
'minutes' => ceil($exception->secondsUntilAvailable / 60),
]));
return null;
}
$data = $this->form->getState();
if (!Filament::auth()->attempt([
'email' => $data['email'],
'password' => $data['password'],
], $data['remember'])) {
$this->addError('email', __('filament::login.messages.failed'));
return null;
}
return app(LoginResponse::class);
}
protected function getFormSchema(): array
{
return [
TextInput::make('email')
->label(__('filament::login.fields.email.label'))
->email()
->required()
->autocomplete(),
TextInput::make('password')
->label(__('filament::login.fields.password.label'))
->password()
->required(),
Checkbox::make('remember')
->label(__('filament::login.fields.remember.label')),
];
}
public function render(): View
{
return view('filament::login')
->layout('filament::components.layouts.card', [
'title' => __('filament::login.title'),
]);
}
}
use App\Filament\Auth\Login;
return [
...
'auth' => [
'pages' => [
'login' => Login::class,
],
],
];
Login page
Now lets customize our blade file. This is default blade file for login page.
<form wire:submit.prevent="authenticate" class="space-y-8">
{{ $this->form }}
<x-filament::button type="submit" form="authenticate" class="w-full">
{{ __('filament::login.buttons.submit.label') }}
</x-filament::button>
</form>
We will add icons for social logins for example facebook, google, etc.
<form wire:submit.prevent="authenticate" class="space-y-8">
{{ $this->form }}
<x-filament::button type="submit" form="authenticate" class="w-full">
{{ __('filament::login.buttons.submit.label') }}
</x-filament::button>
<div class="flex items-center space-x-4">
<div class="border-t-2 border-slate-600 w-full h-1"></div>
<h1>Or</h1>
<div class="border-t-2 border-slate-600 w-full h-1"></div>
</div>
<div class="flex space-x-4 items-center justify-evenly">
// icons from iconify
<span class="iconify w-5 h-5" data-icon="flat-color-icons:google"></span>
<span class="iconify w-5 h-5" data-icon="logos:github-icon"></span>
<span class="iconify w-5 h-5" data-icon="logos:facebook"></span>
</div>
</form>
Example
Lets make a simple example in which email and password will be auto filled when in local environment. This will help us quickly login in local environment. Open Login.php file and on mount method add the following code.
public function mount(): void
{
if(env('APP_ENV') === 'local'){
// fill method is from HasForms interface
$this->form->fill([
'email'=> 'fazailalam898@gmail.com',
'password'=> '12345678',
]);
}else{
$this->form->fill();
}
}
All right all done, now goto https://localhost:8000/admin/login and check for changes.
Posted on August 15, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.