This article is not maintained any longer and likely not up to date. DuckDuckGo might help you find an alternative.
Laravel Forms 101
I need to admit, I always have to look up how forms work in Laravel. So consider this blog post a quick overview – and a cheatsheet for myself in several months.
Here is how a simple form with one input field, say a fullname
, and server-side validation looks like. I will annotate every line. I use TailwindCSS together with the form plugin to get a decent UI with minimal extra markup.
<!-- Blade, e.g. welcome.blade.php -->
<form action="{{ route('form.submit') }}" method="POST" class="space-y-4">
@csrf
<div>
@error('fullname')
<div class="text-red-500">{{ $message }}</div>
@enderror
<label for="fullname">Fullname</label>
<input type="text" name="fullname" value="{{ old('fullname') ?? '' }}" class="form-input">
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
- L1:
action="{{ route('form.submit') }}"
- I use named routes to stay flexible - L1:
method="POST"
- you can setGET
andPOST
directly in the<form>
tag, forPUT/PATCH/DELETE
you would need to add a@method('PUT')
helper in the form - L2:
@csrf
this is to protect your app from submission abuse, if you forget it, you get a419
error (I often forget it…) - L3: Wrap each form element in a
<div>
to style it later (I actually just usespace-y-4
on the form so there will be vertical space between every element on the form… - L4:
@error('fullname')
you can display an error for the field with the namefullname
if it exists - L5:
{{ $message }}
- I often try and fail with{{ $error }}
first, but a good hint is that it's about the error's message… - L7:
<label for="fullname">Fullname</label>
Use the name of the field and a text and put it before the field - L8:
name="fullname"
,name
is what matters to Laravel, notid
. As MDN defines: "Name of the input form control. Submitted with the form as part of a name/value pair." - L8:
value="{{ old('fullname') ?? '' }}"
- this will get the old input if your previous submission did not validate properly and will stay empty if it's a fresh attempt. The??
is called null-coalescing-operator and translates to "If there is an old value, use it, if not, use an empty string" - L11:
<button type="submit">
- I always use a<button>
for submission and not<input type="submit">
because I can put and style content in the buttons body (opposed to onlyvalue="Submit"
on the input)
To get your form working, you need to catch the submission. Here's the code for that with some basic validation:
// routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
Route::get('/', function () {
return view('welcome');
});
Route::post('/submit', function (Request $request) {
$request->validate([
'fullname' => 'required|alpha|min:3',
]);
return 'Submission allowed';
})->name('form.submit');
- L3:
use Illuminate\Support\Facades\Route;
- this is the right import for Routes (your editor might help you with the import) - L4:
use Illuminate\Http\Request;
- this is the only right import for a request (editor might help) - L8:
Route::post('/submit', function (Request $request) { … }
this is how you pass the request to this route callback function - L9:
$request->validate([array])
the array holds the criteria to check the submitted fields - L10:
'fullname' => 'required|alpha
, so the pipe (|
) is the easiest way to separate multiple validations for a field, not,
or;
- L13:
->name('form.submit')
- this is how to give your route a name that you can then use with{{ route('form.submit') }}
in your Blade files