PHPackages                             fridzema/laravel-validation-plus - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. fridzema/laravel-validation-plus

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

fridzema/laravel-validation-plus
================================

Non-blocking validation warnings for Laravel

v1.3.4(1mo ago)05↓100%[4 PRs](https://github.com/fridzema/laravel-validation-plus/pulls)MITPHPPHP ^8.3CI passing

Since Feb 28Pushed 4w agoCompare

[ Source](https://github.com/fridzema/laravel-validation-plus)[ Packagist](https://packagist.org/packages/fridzema/laravel-validation-plus)[ Docs](https://github.com/fridzema/laravel-validation-plus)[ RSS](/packages/fridzema-laravel-validation-plus/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (9)Dependencies (13)Versions (16)Used By (0)

Laravel Validation Plus
=======================

[](#laravel-validation-plus)

[![CI](https://github.com/fridzema/laravel-validation-plus/actions/workflows/ci.yml/badge.svg)](https://github.com/fridzema/laravel-validation-plus/actions/workflows/ci.yml)[![Coverage](https://camo.githubusercontent.com/35a24b8af577dfb1c03f00639a149a50032b73a664877eca983c32e53078d796/68747470733a2f2f636f6465636f762e696f2f67682f667269647a656d612f6c61726176656c2d76616c69646174696f6e2d706c75732f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://codecov.io/gh/fridzema/laravel-validation-plus)[![PHPStan](https://camo.githubusercontent.com/745eb989b9e4903dc598fe2cc63ed4226198be55b7c729001cbd1ece7676fef6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d627269676874677265656e2e737667)](https://phpstan.org)[![Latest Version on Packagist](https://camo.githubusercontent.com/9cd7c1a691a46fcfe946c885c83909cdb6b1c7bab4be479fcc01cc98f7eb209c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f667269647a656d612f6c61726176656c2d76616c69646174696f6e2d706c75732e737667)](https://packagist.org/packages/fridzema/laravel-validation-plus)[![PHP Version](https://camo.githubusercontent.com/1d280aaccc671ee91889f0914ae8cf0c48ae8eb8a4e3ee82178657c7b547fb43/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f667269647a656d612f6c61726176656c2d76616c69646174696f6e2d706c75732e737667)](https://packagist.org/packages/fridzema/laravel-validation-plus)[![License](https://camo.githubusercontent.com/fbb70280499e3b82b6f98f24a7a41a5988d830af3ee5f5552deaa481a1e13d6d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f667269647a656d612f6c61726176656c2d76616c69646174696f6e2d706c75732e737667)](LICENSE.md)

Non-blocking validation warnings for Laravel. Add advisory messages to your form requests that inform users without preventing submission.

How It Works
------------

[](#how-it-works)

Warnings are advisory messages that don't block form submission. Unlike validation errors (red, HTTP 422), warnings (amber) let the request through while informing users about potential issues.

Requirements
------------

[](#requirements)

PackagePHPLaravel1.x^8.311.x, 12.xInstallation
------------

[](#installation)

```
composer require fridzema/laravel-validation-plus
```

Optionally publish the config:

```
php artisan vendor:publish --tag="validation-plus-config"
```

Add the middleware to routes that need warnings:

```
Route::middleware('warnings')->group(function () {
    // your routes
});
```

Usage
-----

[](#usage)

### FormRequest

[](#formrequest)

Add the `HasWarningRules` trait and define `warningRules()`:

```
use Fridzema\ValidationPlus\Traits\HasWarningRules;
use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    use HasWarningRules;

    public function rules(): array
    {
        return [
            'email' => ['required', 'email'],
            'name' => ['required', 'string'],
        ];
    }

    public function warningRules(): array
    {
        return [
            'name' => ['min:3'],
        ];
    }

    public function warningMessages(): array
    {
        return [
            'name.min' => 'Short names may cause display issues.',
        ];
    }

    public function warningAttributes(): array
    {
        return [
            'name' => 'display name',
        ];
    }
}
```

Warning rules are evaluated **after** standard validation passes. If validation fails, warnings are never checked.

MethodPurposeDefault`warningRules()`Rules that trigger warnings`[]``warningMessages()`Custom warning messages`[]``warningAttributes()`Custom field display names (`:attribute` substitution)`[]`### Manual Usage

[](#manual-usage)

Use `WarningValidator` directly in controllers:

```
use Fridzema\ValidationPlus\WarningBag;
use Fridzema\ValidationPlus\WarningValidator;

$validator = app(WarningValidator::class);

$warnings = $validator->validate(
    $request->all(),
    ['name' => 'min:3'],
    ['name.min' => 'Short names may cause display issues.'],
);

// Merge into the scoped bag
app(WarningBag::class)->merge($warnings->getMessages());
```

### Blade

[](#blade)

A `$warnings` variable (a `WarningBag` instance) is automatically shared with all views:

```
@if($warnings->any())

            @foreach($warnings->all() as $warning)
                {{ $warning }}
            @endforeach

@endif
```

Or use the included component:

```

```

Or use the `@warning` directive (mirrors `@error`):

```
@warning('name')
    {{ $message }}
@endwarning
```

### API Responses

[](#api-responses)

When the `ShareWarnings` middleware is active and warnings exist, API responses automatically get:

- An `X-Validation-Warnings: true` header
- Warnings merged into the JSON body under a `"warnings"` key

```
{
    "status": "ok",
    "warnings": {
        "name": ["Short names may cause display issues."]
    }
}
```

### Precognition (Real-Time Validation)

[](#precognition-real-time-validation)

The package integrates with [Laravel Precognition](https://laravel.com/docs/precognition) for real-time per-field warnings as users type.

Real-time warningsReal-time errors[![Precognition Warnings](docs/screenshots/precognition-warnings.png)](docs/screenshots/precognition-warnings.png)[![Precognition Errors](docs/screenshots/precognition-errors.png)](docs/screenshots/precognition-errors.png)Add the `HandlePrecognitiveRequests` middleware to your route:

```
Route::post('/profile', StoreProfileAction::class)
    ->middleware([HandlePrecognitiveRequests::class, 'warnings']);
```

Warning rules are automatically filtered by the `Precognition-Validate-Only` header, so only the field being validated is checked.

Warnings are returned in the `X-Validation-Warnings-Data` response header as JSON:

```
const response = await fetch('/profile', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Precognition': 'true',
        'Precognition-Validate-Only': 'name',
    },
    body: JSON.stringify(form),
});

if (response.status === 204) {
    const warnings = JSON.parse(
        response.headers.get('X-Validation-Warnings-Data') || '{}'
    );
}
```

### Frontend Integration

[](#frontend-integration)

Warnings travel in two ways depending on your setup:

Request typeWarnings locationStandard API (`Accept: application/json`)JSON body under `warnings` keyPrecognition (real-time, `Precognition: true`)`X-Validation-Warnings-Data` header as JSON#### Axios

[](#axios)

An interceptor that surfaces warnings on every response:

```
axios.interceptors.response.use((response) => {
    const header = response.headers['x-validation-warnings-data'];
    response.warnings = header ? JSON.parse(header) : (response.data?.warnings ?? {});
    return response;
});

// Usage
const response = await axios.post('/profile', form);
if (Object.keys(response.warnings).length) {
    console.log(response.warnings); // { name: ['Short names may cause display issues.'] }
}
```

#### Vue 3

[](#vue-3)

```
// composables/useWarnings.js
import { ref } from 'vue';

export function useWarnings() {
    const warnings = ref({});

    function syncFromResponse(response) {
        const header = response.headers?.['x-validation-warnings-data'];
        warnings.value = header ? JSON.parse(header) : (response.data?.warnings ?? {});
    }

    const forField = (field) => warnings.value[field] ?? [];
    const hasWarning = (field) => forField(field).length > 0;
    const clear = () => { warnings.value = {}; };

    return { warnings, syncFromResponse, forField, hasWarning, clear };
}
```

```

import axios from 'axios';
import { reactive } from 'vue';
import { useWarnings } from '@/composables/useWarnings';

const form = reactive({ name: '' });
const { warnings, syncFromResponse, forField } = useWarnings();

async function submit() {
    const response = await axios.post('/profile', form);
    syncFromResponse(response);
}

        {{ msg }}
        Save

```

#### React

[](#react)

```
// hooks/useWarnings.js
import { useState, useCallback } from 'react';

export function useWarnings() {
    const [warnings, setWarnings] = useState({});

    const syncFromResponse = useCallback((response) => {
        const header = response.headers?.['x-validation-warnings-data'];
        setWarnings(header ? JSON.parse(header) : (response.data?.warnings ?? {}));
    }, []);

    const forField = (field) => warnings[field] ?? [];
    const hasWarning = (field) => forField(field).length > 0;
    const clear = () => setWarnings({});

    return { warnings, syncFromResponse, forField, hasWarning, clear };
}
```

```
import axios from 'axios';
import { useState } from 'react';
import { useWarnings } from './hooks/useWarnings';

export function ProfileForm() {
    const [name, setName] = useState('');
    const { syncFromResponse, forField } = useWarnings();

    async function handleSubmit(e) {
        e.preventDefault();
        const response = await axios.post('/profile', { name });
        syncFromResponse(response);
    }

    return (

             setName(e.target.value)} />
            {forField('name').map((msg, i) => (
                {msg}
            ))}
            Save

    );
}
```

#### Alpine.js

[](#alpinejs)

```

        Save

function warningForm() {
    return {
        form: { name: '' },
        warnings: {},
        async submit() {
            const response = await fetch('/profile', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
                body: JSON.stringify(this.form),
            });
            const data = await response.json();
            this.warnings = data.warnings ?? {};
        },
    };
}

```

### Global Warnings

[](#global-warnings)

For advisory messages not tied to a specific field:

```
warnings()->addGlobal('Your account is approaching its storage limit.');
app(WarningBag::class)->addGlobal('Subscription expires in 3 days.');
```

Access them in Blade with the reserved `__global__` key:

```
@warning('__global__')
    {{ $message }}
@endwarning
```

### Helper Function

[](#helper-function)

```
$bag = warnings(); // returns the scoped WarningBag
```

Testing
-------

[](#testing)

Test macros are registered automatically:

```
$response = $this->postJson('/api/users', [
    'email' => 'test@example.com',
    'name' => 'Jo',
]);

$response->assertOk();
$response->assertHasWarning('name');
$response->assertHasWarning('name', 'Short names may cause display issues.');
$response->assertHasNoWarnings('email');
$response->assertHasNoWarnings();                                           // no warnings at all
$response->assertWarnings(['name' => ['Short names may cause display issues.']]);  // exact shape
```

Configuration
-------------

[](#configuration)

```
return [
    // HTTP header added to API responses when warnings exist
    'header' => 'X-Validation-Warnings',

    // Merge warnings into JSON response body under the json_key
    'inject_json' => true,

    // JSON body key used when injecting warnings into API responses
    'json_key' => 'warnings',

    // Session key for flashing warnings on web requests
    'session_key' => 'warnings',
];
```

Warnings vs Errors
------------------

[](#warnings-vs-errors)

ErrorsWarningsBlock requestYesNoCause validation failureYesNoHTTP status422200 (original)Blade variable`$errors``$warnings`Session flashAutomaticVia middlewareAPI responseStandard LaravelHeader + JSON keyOctane Compatibility
--------------------

[](#octane-compatibility)

`WarningBag` uses a scoped binding and is reset between requests automatically by Laravel Octane. No extra configuration needed.

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance94

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 86% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Recently: every ~0 days

Total

11

Last Release

33d ago

Major Versions

v0.0.0 → v1.0.02026-03-03

PHP version history (2 changes)v0.0.0PHP ^8.2

v1.1.0PHP ^8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/8180660?v=4)[Robert Fridzema](/maintainers/fridzema)[@fridzema](https://github.com/fridzema)

---

Top Contributors

[![fridzema](https://avatars.githubusercontent.com/u/8180660?v=4)](https://github.com/fridzema "fridzema (37 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (6 commits)")

---

Tags

laravelvalidationwarningsfridzemalaravel-validation-plus

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/fridzema-laravel-validation-plus/health.svg)

```
[![Health](https://phpackages.com/badges/fridzema-laravel-validation-plus/health.svg)](https://phpackages.com/packages/fridzema-laravel-validation-plus)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k98.0M1.3k](/packages/spatie-laravel-permission)[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.3M41](/packages/spatie-laravel-pdf)[dedoc/scramble

Automatic generation of API documentation for Laravel applications.

2.1k9.9M87](/packages/dedoc-scramble)[spatie/laravel-health

Monitor the health of a Laravel application

88011.3M149](/packages/spatie-laravel-health)[spatie/laravel-passkeys

Use passkeys in your Laravel app

463755.5k32](/packages/spatie-laravel-passkeys)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
