Skip to content

Fix explicit named slots ommited during component folding - #211

Merged
ganyicz merged 2 commits into
livewire:mainfrom
ghabriel25:fix/named-slot
Sep 12, 2026
Merged

Fix explicit named slots ommited during component folding#211
ganyicz merged 2 commits into
livewire:mainfrom
ghabriel25:fix/named-slot

Conversation

@ghabriel25

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #209: whitespace-only explicit named slots are registered as empty slots during folding instead of being dropped.

Problem

#209 correctly avoided creating non-empty placeholders for whitespace-only content (placeholders made $slot->isEmpty() false during fold-time pre-render).

For explicit named slots it used continue, so the slot was omitted from $__slots during pre-render:

<x-card>
    <x-slot:footer> </x-slot>
</x-card>
Path $footer during fold pre-render
Blade / SlotCompiler (runtime) Defined, ComponentSlot('') after trim()
Fold after #209 Undefined (missing from $__slots)

Fold treats slots as pass-through (placeholder → restore). Omitting the slot can break pre-render of templates that echo the named slot ({{ $footer }}) when the only content is whitespace.

Default $slot is unaffected: Wrapper already does $__slots['slot'] ??= new ComponentSlot('').

Changes

In Foldable::setupSlots(), always register explicit slots:

  • Has real content → placeholder TextNode + slotByPlaceholder (unchanged)
  • Whitespace-only / empty → empty children ([]), no placeholder
$children = [];

if ($this->hasActualContent($child->children)) {
    $placeholder = 'BLAZE_PLACEHOLDER_' . $this->placeholderIndex++ . '_';
    $this->slotByPlaceholder[$placeholder] = $child;
    $children = [new TextNode($placeholder)];
}

$slots[$child->name] = new SlotNode(
    // ...
    children: $children,
    // ...
);

Implicit default-slot behavior from #209 is unchanged: whitespace-only loose content does not synthesize a default slot.

@ghabriel25

Copy link
Copy Markdown
Contributor Author

@ganyicz Could you review this? I think I made a regression from previous PR, thanks!

@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Benchmark Result: Default

Attempt Blade Blaze Change
#1 367.07ms 14.85ms 96%
#2 367.89ms 14.91ms 95.9%
#3 359.84ms 14.92ms 95.9%
#4 361.36ms 14.96ms 95.9%
#5 356.38ms 14.74ms 95.9%
#6 360.46ms 15.09ms 95.8%
#7 364.54ms 14.95ms 95.9%
#8 363.75ms 15.01ms 95.9%
#9 * 369.80ms 15.22ms 95.9%
#10 363.19ms 15.03ms 95.9%
Snapshot 364.54ms 14.79ms 95.9%
Result 363.19ms (~) 14.95ms (~) 95.9% (~)

Median of 10 attempts (* = outlier, excluded from result), 5000 iterations x 10 rounds, 47.74s total

To run a specific benchmark, comment /benchmark <name>
attributes, aware, class, default, forwarding, merge, named-slots, no-attributes, slot, compilation

@ganyicz

ganyicz commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

Oof good catch, thanks @ghabriel25

@ganyicz
ganyicz merged commit ce599a8 into livewire:main Sep 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants