Fix wire:model warnings and ensure truly unique HTML IDs

**Problems Fixed:**
1. Livewire warnings about non-existent properties (e.g., wire:model="dcgoowgw0gcgcsgg00c8kskc")
2. Duplicate HTML IDs still appearing despite initial fix

**Root Causes:**
1. Auto-generated Cuid2 IDs were being used for wire:model when no explicit id was provided
2. Livewire's wire:id attribute isn't available during server-side rendering

**Solutions:**
1. Set $modelBinding to 'null' (string) when id is not provided, preventing invalid wire:model generation
2. Use random MD5 suffix instead of Livewire component ID for guaranteed uniqueness during initial render
3. Maintain correct $name attribute based on original property name

**Technical Changes:**
- Input, Textarea, Select, Datalist: Use random 8-char suffix for uniqueness
- Checkbox: Apply same random suffix approach
- wire:model now only created for explicit property names
- HTML IDs are unique from initial server render (no hydration required)

**Result:**
 No more Livewire property warnings
 Truly unique HTML IDs across all components
 wire:model bindings work correctly
 Validation and form submission unaffected

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai 2025-10-14 10:32:49 +02:00
parent a514c837b6
commit 598984f291
5 changed files with 43 additions and 34 deletions

View file

@ -53,14 +53,14 @@ public function render(): View|Closure|string
{
// Store original ID for wire:model binding (property name)
$this->modelBinding = $this->id;
$this->htmlId = $this->id;
// Generate unique HTML ID by prefixing with Livewire component ID if available
// Generate unique HTML ID by adding random suffix
// This prevents duplicate IDs when multiple forms are on the same page
if ($this->id) {
$livewireId = $this->attributes?->wire('id');
if ($livewireId) {
$this->htmlId = $livewireId.'-'.$this->id;
}
$uniqueSuffix = substr(md5(uniqid((string) mt_rand(), true)), 0, 8);
$this->htmlId = $this->id.'-'.$uniqueSuffix;
} else {
$this->htmlId = $this->id;
}
return view('components.forms.checkbox');

View file

@ -56,20 +56,22 @@ public function render(): View|Closure|string
if (is_null($this->id)) {
$this->id = new Cuid2;
$this->modelBinding = $this->id;
// Don't create wire:model binding for auto-generated IDs
$this->modelBinding = 'null';
}
// Generate unique HTML ID by prefixing with Livewire component ID
// Generate unique HTML ID by adding random suffix
// This prevents duplicate IDs when multiple forms are on the same page
$livewireId = $this->attributes?->wire('id');
if ($livewireId && $this->modelBinding) {
$this->htmlId = $livewireId.'-'.$this->modelBinding;
if ($this->modelBinding && $this->modelBinding !== 'null') {
// Use original ID with random suffix for uniqueness
$uniqueSuffix = substr(md5(uniqid((string) mt_rand(), true)), 0, 8);
$this->htmlId = $this->modelBinding.'-'.$uniqueSuffix;
} else {
$this->htmlId = $this->modelBinding ?: $this->id;
$this->htmlId = (string) $this->id;
}
if (is_null($this->name)) {
$this->name = $this->modelBinding;
$this->name = $this->modelBinding !== 'null' ? $this->modelBinding : (string) $this->id;
}
return view('components.forms.datalist');

View file

@ -52,19 +52,22 @@ public function render(): View|Closure|string
if (is_null($this->id)) {
$this->id = new Cuid2;
$this->modelBinding = $this->id;
// Don't create wire:model binding for auto-generated IDs
$this->modelBinding = 'null';
}
// Generate unique HTML ID by prefixing with Livewire component ID
// Generate unique HTML ID by adding random suffix
// This prevents duplicate IDs when multiple forms are on the same page
$livewireId = $this->attributes?->wire('id');
if ($livewireId && $this->modelBinding) {
$this->htmlId = $livewireId.'-'.$this->modelBinding;
if ($this->modelBinding && $this->modelBinding !== 'null') {
// Use original ID with random suffix for uniqueness
$uniqueSuffix = substr(md5(uniqid((string) mt_rand(), true)), 0, 8);
$this->htmlId = $this->modelBinding.'-'.$uniqueSuffix;
} else {
$this->htmlId = $this->modelBinding ?: $this->id;
$this->htmlId = (string) $this->id;
}
if (is_null($this->name)) {
$this->name = $this->modelBinding;
$this->name = $this->modelBinding !== 'null' ? $this->modelBinding : (string) $this->id;
}
if ($this->type === 'password') {
$this->defaultClass = $this->defaultClass.' pr-[2.8rem]';

View file

@ -49,20 +49,22 @@ public function render(): View|Closure|string
if (is_null($this->id)) {
$this->id = new Cuid2;
$this->modelBinding = $this->id;
// Don't create wire:model binding for auto-generated IDs
$this->modelBinding = 'null';
}
// Generate unique HTML ID by prefixing with Livewire component ID
// Generate unique HTML ID by adding random suffix
// This prevents duplicate IDs when multiple forms are on the same page
$livewireId = $this->attributes?->wire('id');
if ($livewireId && $this->modelBinding) {
$this->htmlId = $livewireId.'-'.$this->modelBinding;
if ($this->modelBinding && $this->modelBinding !== 'null') {
// Use original ID with random suffix for uniqueness
$uniqueSuffix = substr(md5(uniqid((string) mt_rand(), true)), 0, 8);
$this->htmlId = $this->modelBinding.'-'.$uniqueSuffix;
} else {
$this->htmlId = $this->modelBinding ?: $this->id;
$this->htmlId = (string) $this->id;
}
if (is_null($this->name)) {
$this->name = $this->modelBinding;
$this->name = $this->modelBinding !== 'null' ? $this->modelBinding : (string) $this->id;
}
return view('components.forms.select');

View file

@ -62,20 +62,22 @@ public function render(): View|Closure|string
if (is_null($this->id)) {
$this->id = new Cuid2;
$this->modelBinding = $this->id;
// Don't create wire:model binding for auto-generated IDs
$this->modelBinding = 'null';
}
// Generate unique HTML ID by prefixing with Livewire component ID
// Generate unique HTML ID by adding random suffix
// This prevents duplicate IDs when multiple forms are on the same page
$livewireId = $this->attributes?->wire('id');
if ($livewireId && $this->modelBinding) {
$this->htmlId = $livewireId.'-'.$this->modelBinding;
if ($this->modelBinding && $this->modelBinding !== 'null') {
// Use original ID with random suffix for uniqueness
$uniqueSuffix = substr(md5(uniqid((string) mt_rand(), true)), 0, 8);
$this->htmlId = $this->modelBinding.'-'.$uniqueSuffix;
} else {
$this->htmlId = $this->modelBinding ?: $this->id;
$this->htmlId = (string) $this->id;
}
if (is_null($this->name)) {
$this->name = $this->modelBinding;
$this->name = $this->modelBinding !== 'null' ? $this->modelBinding : (string) $this->id;
}
// $this->label = Str::title($this->label);