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 setGETandPOSTdirectly in the<form>tag, forPUT/PATCH/DELETEyou would need to add a@method('PUT')helper in the form - L2:
@csrfthis is to protect your app from submission abuse, if you forget it, you get a419error (I often forget it…) - L3: Wrap each form element in a
<div>to style it later (I actually just usespace-y-4on 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 namefullnameif 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",nameis 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