Skip to content

Mark unsafe forwarded props#2496

Merged
calebporzio merged 1 commit intomainfrom
filip/fix-blaze-delegate
Mar 23, 2026
Merged

Mark unsafe forwarded props#2496
calebporzio merged 1 commit intomainfrom
filip/fix-blaze-delegate

Conversation

@ganyicz
Copy link
Copy Markdown
Collaborator

@ganyicz ganyicz commented Mar 16, 2026

The scenario

When using Blaze, attributes forwarded through <flux:with-field> or <flux:delegate-component> don't work correctly when passed as dynamic PHP variables:

@php($label = null)

<flux:select :label="$label" />

The above always renders ui-label despite $label being null.

The problem

Blaze treats props as "safe" (foldable at compile time) when they're not declared in the component's own @props. Forwarded props like label, description, error:name, etc. are defined in a different file (with-field.blade.php), so Blaze can't see them and folds them as static values.

The solution

Manually declare all forwarded props as unsafe in the @blaze directive of each affected component.

Fixes #2458

@calebporzio
Copy link
Copy Markdown
Contributor

ugh sheesh that's annoying. And doing it this way will create a duplication of knowledge right? the props in the inner component and the unsafe listing in the outer component. Is there no better way...??

@claude ? (do we even have claude on this repo lol?)

@ganyicz
Copy link
Copy Markdown
Collaborator Author

ganyicz commented Mar 20, 2026

I summoned Claude locally, it should chime in.

The only potentially-slightly-better way would be to have more knowledge of flux:delegate-component and passing through attributes (recursively) in Blaze. Not a big fan of more coupling with flux and tracking of recursive attribute forwarding is a mess and a performance impact, I had that implemented at some point.

@ganyicz
Copy link
Copy Markdown
Collaborator Author

ganyicz commented Mar 20, 2026

Hey @calebporzio — I looked at this PR and the Blaze source code in depth. Here's my understanding and thoughts:

The root cause

In Blaze's Folder::isSafeToFold(), the safety logic works like this:

  1. Props declared in the component's own @props are added to the unsafe list (line 144 of Folder.php)
  2. If a dynamic attribute is NOT in @props, it's considered safe to fold — Blaze assumes it just passes through $attributes without affecting the rendered output

This assumption breaks when a component delegates to with-field or delegate-component, because those forwarded attributes absolutely DO affect the rendered output of children. Since label, description, etc. aren't in the outer component's @props, Blaze folds them as static values.

Is there a better way?

The duplication concern is valid — every component that uses with-field needs to copy the same list of props into unsafe: [...], and if with-field ever gains new props, every consumer needs updating.

A potential Blaze-level feature that could help: something like unsafe_from:

@blaze(fold: true, unsafe_from: ['flux::with-field'])

This would tell Blaze: "look up flux::with-field's @props and add them to this component's unsafe list." Single source of truth, no duplication. It's a one-time lookup per component compilation (no recursive tracking), and it makes the forwarding relationship explicit in the directive.

The outer components would go from this:

@blaze(fold: true, unsafe: [
    'name', 'label', 'badge',
    'description', 'description:trailing',
    'label:badge', 'label:aside', 'label:trailing',
    'error:name', 'error:bag', 'error:message', 'error:icon', 'error:nested', 'error:deep',
])

To this:

@blaze(fold: true, unsafe_from: ['flux::with-field'])

Other alternatives I considered:

  • unsafe: ['attributes'] already exists in Blaze and marks all non-@props attributes as unsafe, but it's too aggressive — it would prevent folding whenever any dynamic non-prop attribute is passed, even ones that don't get forwarded
  • Auto-detecting forwarding from delegate-component / with-field usage — Filip already mentioned he tried recursive attribute tracking and it was complex + a performance hit. Agreed that's not worth it.

Bottom line

This PR is correct and solves the bug. If the duplication bothers you, unsafe_from would be a clean Blaze-level feature to eliminate it. But that's an enhancement for Blaze, not a blocker for this fix.

@ganyicz
Copy link
Copy Markdown
Collaborator Author

ganyicz commented Mar 20, 2026

Yeah something unsafe_from would make it more maintainable.

@calebporzio
Copy link
Copy Markdown
Contributor

well...clearly we can't punt on this because it's currently a bug...but...I don't like any of the solutions haha.

Adding unsafe_from is the kind of thing that will make this package feel impossible to understand and use for someone not deeply initiated into the headspace.

Marking nested attribute forwarding props I think is better even though it's bad lol. And I don't think too many people forward attributes in the way that we do, but i could be wrong.

From a DX perspective, intelligently accounting for this without making the dev think about it is the only way.

Another valid option is somehow getting away from with-field attribute forwarding and such. Maybe get away from with-field in general? idk...

I have no solutions, but I can at least prevent or slow us from making a bad choice.

@ganyicz
Copy link
Copy Markdown
Collaborator Author

ganyicz commented Mar 21, 2026

I don't like the solutions either lol.

The one applied in this PR is the least offensive imo, it just makes maintainability worse. But it's an actual fix that we can merge, doesn't require adding any special APIs. We just need to keep this in mind when adding new properties to with-fields or variants. Perhaps we could come up with an automated way to check this?

I don't think the attribute forwarding we do here is common at all. In user-land you would just disable fold for a component that does this.

getting away from with-field attribute forwarding and such

This is the ideal fix, but it would require a massive rewrite, probably best to leave for Flux v3.

My recommendation would be:

  1. Add some way to check this automatically so we don't create bugs when adding new props
  2. Merge this
  3. Eliminate in v3

From a DX perspective, intelligently accounting for this without making the dev think about it is the only way.

Agreed, if this was in user-land. But this is an obscure need of Flux (and could be eliminated). Tracking of the props is a huge lift, adds extra file reads, computation and makes compilation slower. For making a better DX of something only we deal with.

@calebporzio
Copy link
Copy Markdown
Contributor

Ok, yeah is there something automated or almost automated we could do? there are other things like this. like checking that the right free/pro components are in the publish command list (which I'm now realizing i might not have added timeline and slider lol). And that like kinda thing is in the flux docs for the pro components. you know anything that could drift, it would be nice to have a setup for.

maybe we have a few /check-*** skills that get run either for PRs or pre-release? probably makes the most sense for them to be either post-merge or pre-release so that they don't take too long or too many tokens and hold up PRs.

We probably need some kind of automated release tool at this point. (we're manually checking the composer.json flux/flux-pro version matches as well)

So maybe we make a single /prep-release claude skill that runs through all these things. whadyathink?

@ganyicz
Copy link
Copy Markdown
Collaborator Author

ganyicz commented Mar 21, 2026

I like the idea of automated checks a lot. I'll put something together.

But I would try to make them deterministic, the release process should be 100% reliable I believe. Agree?

@calebporzio
Copy link
Copy Markdown
Contributor

meh, idk. but deterministic is definitely better if possible, so not gonna fight you on that

@calebporzio calebporzio merged commit d0202a2 into main Mar 23, 2026
@calebporzio calebporzio deleted the filip/fix-blaze-delegate branch March 23, 2026 15:03
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.

Select, Blaze folding

2 participants