Laravel Forms 101
Published: 2020-07-09 19:41:37

---
title: Laravel Forms 101
published: true
date: 2020-07-08 01:21:14 UTC
tags: 
canonical_url: https://martinbetz.eu/article/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](tailwindcss.com/) together with the [form plugin](https://github.com/tailwindcss/custom-forms) 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](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname) 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](https://stitcher.io/blog/shorthand-comparisons-in-php#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