DEV Community

Martin Betz
Martin Betz

Posted on • Originally published at martinbetz.eu on

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 set GET and POST directly in the <form> tag, for PUT/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 a 419 error (I often forget it…)
  • L3: Wrap each form element in a <div> to style it later (I actually just use space-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 name fullname 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, not id. 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 only value="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

Top comments (0)