mrpunyapal/laravel-client-validation
Bring Laravel-style validation to the client with 100+ rules plus AJAX-backed unique/exists checks. TypeScript-ready, works with any backend, and integrates with Livewire, Filament, Alpine, or vanilla/React/Vue for real-time form feedback and FormRequest rule reuse.
## Getting Started
### Minimal Setup
1. **Install the package** via Composer:
```bash
composer require mrpunyapal/laravel-client-validation
php artisan client-validation:install
This publishes the config file and sets up the package.
Basic Alpine.js usage (most common workflow):
<input x-validate="'required|email'" name="email">
This applies Laravel-style validation rules (required|email) to the input field on blur (default behavior).
First use case: Validate a form field in real-time with minimal setup:
<div x-data="{ validation: validation({
rules: { email: 'required|email' }
}) }">
<input x-model="validation.form.email" @blur="validation.validate('email')">
<span x-text="validation.error('email')" x-show="validation.hasError('email')"></span>
</div>
x-validate directive (e.g., x-validate="'required|email'").x-wire-validate directive or the PHP trait.HasClientValidation trait.data-validate attributes or programmatic validation.<div x-data="validation({
rules: {
email: 'required|email|unique:users,email',
password: 'required|min:8|confirmed:password_confirmation'
},
messages: {
'email.required': 'Please enter your email',
'password.min': 'Password must be at least 8 characters'
}
})">
<form @submit.prevent="submit(async (data) => {
// Submit valid data to server
})">
<input x-model="form.email" @blur="validate('email')">
<span x-text="error('email')" x-show="hasError('email')"></span>
<input type="password" x-model="form.password" @blur="validate('password')">
<span x-text="error('password')" x-show="hasError('password')"></span>
<input type="password" x-model="form.password_confirmation">
</form>
</div>
Pattern: Use validation() component for full form control. Validate fields on blur by default, but switch to live or submit modes as needed.
<input x-validate="'required|min:{{ minLength }}'" name="username">
Pattern: Use Alpine.js reactivity to dynamically update validation rules.
// In Livewire component
use MrPunyapal\ClientValidation\Livewire\WithClientValidation;
class CreateUser extends Component
{
use WithClientValidation;
public string $email = '';
public string $password = '';
protected $rules = [
'email' => 'required|email',
'password' => 'required|min:8',
];
public function render()
{
return view('livewire.create-user');
}
}
<!-- In Blade view -->
<div x-data="{ clientRules: @json($this->getClientRules()) }">
<input wire:model="email"
x-wire-validate="clientRules.email"
name="email">
</div>
Pattern: Use WithClientValidation trait to auto-generate client-side rules from $rules. Sync Livewire model updates with client validation.
protected $listeners = [
'client-validation-error' => 'handleClientError',
];
public function handleClientError($data)
{
// Handle client-side errors (e.g., update UI)
}
Pattern: Listen to client validation events to update Livewire state or UI without full page reloads.
use MrPunyapal\ClientValidation\Filament\ClientValidatedField;
ClientValidatedField::make('email')
->clientValidation('required|email')
->clientValidationMode('live');
Pattern: Use ClientValidatedField for Filament forms. Configure validation mode (blur, live, or submit) per field.
ClientValidationPlugin::make()
->enableRemoteValidation()
->validationMode('live');
Pattern: Register the plugin in AdminPanelProvider to enable global client validation.
<input x-validate.live="'required|email|unique:users,email'"
name="email">
Pattern: Use remote rules (unique, exists) with .live or .submit modifiers for real-time or on-submit validation.
const remote = new RemoteValidator({
endpoint: '/api/validate',
requestFormatter: (field, value, rule, params) => ({
field_name: field,
field_value: value,
validation_rule: rule,
rule_params: params
})
});
Pattern: Configure RemoteValidator for non-Laravel backends (e.g., Express, Django). Use requestFormatter to match your API expectations.
// Controller
public function create()
{
$validation = ClientValidation::fromRequest(CreateUserRequest::class);
return view('users.create', compact('validation'));
}
<div x-data="validation(@js($validation))">
<!-- Form fields -->
</div>
Pattern: Extract client-side rules from FormRequest classes using ClientValidation::fromRequest(). Pass the rules to Alpine.js for seamless reuse.
<form data-validate>
<input name="email"
data-rules="required|email"
data-validate-on="blur">
</form>
Pattern: Use data-validate and data-rules attributes for lightweight validation without frameworks.
import { LaravelValidator } from 'laravel-client-validation/core';
const validator = new LaravelValidator({
rules: { email: 'required|email' }
});
const result = await validator.validateField('email', 'test@example.com');
Pattern: Use LaravelValidator for custom validation logic (e.g., in React/Vue components or utility functions).
Remote Rule Timing:
unique, exists) trigger AJAX requests. Ensure your backend endpoint is configured correctly (e.g., CSRF protection, rate limiting).debounce_ms in config to avoid excessive requests:
'debounce_ms' => 500, // 500ms delay for live validation
Livewire Version Conflicts:
x-wire-validate) may behave differently.'livewire_version' => 'v4',
Alpine.js Scope Issues:
x-data blocks may not inherit validation state.x-model with explicit field names.CSRF Token for Remote Validation:
RemoteValidator to include tokens:
const remote = new RemoteValidator({
csrfHeaderName: 'X-CSRF-TOKEN',
csrfTokenResolver: () => document.querySelector('meta[name="csrf-token"]')?.content
});
Rule Parameter Escaping:
min:{{ minLength }}) must be sanitized to avoid XSS.text binding or sanitize parameters server-side:
<input x-validate="'required|min:' + minLength" name="username">
Filament Field Initialization:
HasClientValidation must call initializeClientValidation() in their constructor.ClientValidatedField or manually initialize:
public function __construct()
{
parent::__construct();
$this->initializeClientValidation();
}
Validation Logs:
'debug' => true,
client-validation:debug logs.Rule Testing:
LaravelValidator:
const validator = new LaravelValidator();
console.log(validator.testRule('email', 'test@example.com', 'required'));
How can I help you explore Laravel packages today?